<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>晴耕雨讀</title><link>http://0x3f.org/</link><description>Recent content on 晴耕雨讀</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>© 2007-2024 鬼马妖刀</copyright><lastBuildDate>Tue, 07 Apr 2026 23:58:08 +0800</lastBuildDate><atom:link href="http://0x3f.org/index.xml" rel="self" type="application/rss+xml"/><item><title>飞鱼变速不准，罪魁祸首竟然是它！</title><link>http://0x3f.org/posts/feiyu-shifting-issue-caused-by-sunshine-cassette/</link><pubDate>Tue, 07 Apr 2026 23:58:08 +0800</pubDate><guid>http://0x3f.org/posts/feiyu-shifting-issue-caused-by-sunshine-cassette/</guid><description>&lt;p&gt;我这辆飞鱼，为了减重选了日晖超轻飞轮，一直有个变速的问题。&lt;/p&gt;
&lt;p&gt;从小飞往大飞连续变速（手变摁到底），大概率会出现变速不准的问题，此时再往小飞进一档就正常了，而逐档变速出现同样问题的概率很小。&lt;/p&gt;
&lt;p&gt;一开始以为是后拨没调好，但调了一下也没解决。思来想去只有飞轮跟别人的不一样，于是把日晖超轻飞轮换成禧玛诺 R7000 ，问题就没了。&lt;/p&gt;
&lt;p&gt;据说同样的日晖飞轮，用电子变速不会有这个问题。我猜测，日晖超轻飞轮较大的几片是铝合金，刚性不足，加上飞轮本身有公差，而飞鱼这车的走线比较绕导致线阻变大，这几个因素综合起来放大了这个问题。禧玛诺飞轮是全钢的，刚性好，对线阻误差的包容度高，所以没问题。电子变速是电机驱动，不受线阻影响，每次移动量固定，更精准，也能弥补日晖飞轮的公差和刚性不足。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260408000434036-0642225e3333dd059b51598731f1eb3a.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>终于找到了满意的煮茶壶</title><link>http://0x3f.org/posts/tea-kettle-found/</link><pubDate>Tue, 31 Mar 2026 10:00:00 +0800</pubDate><guid>http://0x3f.org/posts/tea-kettle-found/</guid><description>&lt;p&gt;常见的提梁壶有几个问题：提梁在正上方，容易烫手。提梁用螺丝固定，有脱落的风险。壶嘴内口较低，水放得稍微多点容易溅出来。&lt;/p&gt;
&lt;p&gt;所以重点在侧面一体把手的壶里找，看了几个，要么容量太大，要么必须配合内胆使用。多数玻璃壶的壶盖在不装内胆的情况下都非常松，我的投茶量不大，水不能没过内胆中的茶叶，所以不适合用内胆。找来找去，终于找到这款直接盖盖也不松的壶，容量也合适。&lt;/p&gt;
&lt;p&gt;不过这个壶的壶嘴断水不行，容易挂水，内胆也没有喷淋管，美中不足。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260331235920382-eca9766ffedefa49b25bdf2601843845.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>一年后，我卖掉了那辆小布</title><link>http://0x3f.org/posts/sold-my-brompton-after-one-year/</link><pubDate>Mon, 30 Mar 2026 10:00:00 +0800</pubDate><guid>http://0x3f.org/posts/sold-my-brompton-after-one-year/</guid><description>&lt;p&gt;他们给的太多了，于是我为期一年的英布车主生涯毕业了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260330211829071-66a15f84d902cf0e91dd5b2ade9d41c8.avif" alt="20260330211829071-66a15f84d902cf0e91dd5b2ade9d41c8"&gt;&lt;/p&gt;
&lt;p&gt;说说感受吧。&lt;/p&gt;
&lt;h1 id="英布和国布的对比"&gt;英布和国布的对比&lt;/h1&gt;
&lt;p&gt;英布的骑感很整。倒不是说国布骑着就松垮，但是英布的这种骑感确实比国布好。&lt;/p&gt;
&lt;p&gt;英布的路感表现更好。按说我的国布也是铬钼钢车架、铜焊，但是相同胎压的情况下，路感明显要比英布清晰。&lt;/p&gt;
&lt;p&gt;英布的刹感很线性。即便我的国布用英布原厂的刹把、夹器和 DA 线管改装后，刹感大幅改善，但和英布相比还是有所不如。当然，这不一定是国布的问题。&lt;/p&gt;
&lt;p&gt;外观的质感比国布好很多。几乎所有的国布以及英布的改装件都喜欢用那种 bling bling 的风格。但是，堆砌金属感并不等于质感，对感官的刺激越强烈，就越容易审美疲劳。而且改装件也不像原厂件，会考虑到整车外观的一致性。我没见过任何一辆改装后的小布，像原车一样耐看。&lt;/p&gt;
&lt;p&gt;我的国布的优势是轮组非常润，编制也很好，有种骑起来停不下来的感觉。外七速的变速非常好使，尤其是换了 SRAM 的指拨后，变速手感很干脆，很精准。外挂培林中轴很轻、很润，曲柄牙盘的刚性也比英布的好。&lt;/p&gt;
&lt;h1 id="关于好骑"&gt;关于好骑&lt;/h1&gt;
&lt;p&gt;如果不觉得好骑等于骑得快，那么英布绝对算是一辆非常好骑的车。骑起来很舒服，很放松。反而我骑那些很快的车的时候，会比较焦虑。如果觉得能骑快才是好骑，那就直接考虑别的车。不管是英布还是国布，重量、刚性、轮径、几何决定了这个车型的性能天花板很低。小布性能向的改装就是缘木求鱼、屎上雕花。&lt;/p&gt;
&lt;h1 id="英布和国布怎么选"&gt;英布和国布怎么选&lt;/h1&gt;
&lt;p&gt;反正新版四速 C-Line 出来之后，我觉得国布除了卷性价比，没有别的出路了。最近 Mint 新出了个 1000 多的 Bob 5，我觉得路子相当对啊。1比1英布，改装也方便，随便改改，就是一辆挺好的车。总之，只想踏实骑车，不愿意折腾，对外观有要求的选英布。其它选国布。&lt;/p&gt;
&lt;h1 id="英布怎么选"&gt;英布怎么选&lt;/h1&gt;
&lt;p&gt;四速 C-Line 里挑一个最喜欢的颜色即可，其它都是走弯路。&lt;/p&gt;
&lt;h1 id="关于买不买小布"&gt;关于买不买小布&lt;/h1&gt;
&lt;p&gt;取决于对便携性和情绪价值是不是刚需。所谓刚需，是已经在做且无法替代的，不是想像出来的需求。比如通勤是刚需，骑游就是可替代的。我曾经觉得带小布转乘公共交通工具去远地方骑车应该挺不错，但后来宁愿坐货拉拉带辆更好骑的车，综合体验会更好。这就是想像出来的需求。&lt;/p&gt;
&lt;p&gt;至于情绪价值，喝杯咖啡，拍个照，满足一下中产阶级的想像，也没什么不好的，情绪价值也是价值。骑车不是只能挂满传感器盯着表骑，踏频速度刷 PR 不是骑车的唯一乐趣，手势蹭风小火车也不是唯一中二的骑法，开心就行。只不过我已经过了这个阶段了，爬戒台寺从不消费，咖啡、照片、各种文文艺艺的小确幸，抓不住的都是镜花水月，我现在觉得大棉袄二棉裤没什么不好的。&lt;/p&gt;
&lt;h1 id="关于退坑"&gt;关于退坑&lt;/h1&gt;
&lt;p&gt;只是暂时没有刚需，坑就在那儿，会回来的。&lt;/p&gt;</description></item><item><title>OpenClash 升级后我这样找回了自定义策略组</title><link>http://0x3f.org/posts/openclash-custom-proxy-groups-with-subconverter/</link><pubDate>Thu, 19 Mar 2026 18:00:00 +0800</pubDate><guid>http://0x3f.org/posts/openclash-custom-proxy-groups-with-subconverter/</guid><description>&lt;p&gt;OpenClash v0.47.071 移除了&amp;quot;一键生成&amp;quot;功能。&lt;/p&gt;
&lt;p&gt;这个功能之前可以在订阅配置的基础上插入自定义策略组。比如我会按地区筛选节点，组成几个专用的策略组，方便日常切换。升级之后这些自定义策略组全部失效了。&lt;/p&gt;
&lt;p&gt;官方推荐用订阅转换来替代一键生成。订阅转换是一个中间服务，把机场提供的订阅链接转换成各种客户端能用的配置文件，转换过程中可以注入自定义的策略组和规则。&lt;/p&gt;
&lt;h2 id="部署-subconverter"&gt;部署 Subconverter&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/MetaCubeX/subconverter"&gt;Subconverter&lt;/a&gt; 是一个常用的开源订阅转换工具。用 Docker 部署很简单：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;subconverter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ghcr.io/metacubex/subconverter:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;subconverter&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;25500:25500&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/root/appdata/subconverter/pref.toml:/base/pref.toml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/root/appdata/subconverter/snippets/custom_groups.toml:/base/snippets/custom_groups.toml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Subconverter 的容器镜像自带了一套完整的默认配置，包括标准策略组、规则集和模板文件，都放在容器的 &lt;code&gt;/base&lt;/code&gt; 目录下。只需要把要自定义的文件挂载进去，&lt;code&gt;pref.toml&lt;/code&gt; 是主配置文件，&lt;code&gt;custom_groups.toml&lt;/code&gt; 是自定义策略组，其余全部保留容器默认的。&lt;/p&gt;
&lt;h2 id="配置自定义策略组"&gt;配置自定义策略组&lt;/h2&gt;
&lt;p&gt;Subconverter 的默认配置里已经有一套标准策略组（节点选择、自动选择、Netflix、Telegram 等）和对应的规则集。我只需要额外添加自己的策略组就行。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;pref.toml&lt;/code&gt; 里，通过 import 把默认策略组和自定义策略组分开管理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;custom_groups&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;import&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;snippets/groups.toml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;custom_groups&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;import&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;snippets/custom_groups.toml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;groups.toml&lt;/code&gt; 是容器自带的，不用动。&lt;code&gt;custom_groups.toml&lt;/code&gt; 是自己的，内容类似这样：&lt;/p&gt;</description></item><item><title>家里网络卡了两天，原来是这个“优化”在作祟</title><link>http://0x3f.org/posts/home-network-lag/</link><pubDate>Mon, 16 Mar 2026 18:00:00 +0800</pubDate><guid>http://0x3f.org/posts/home-network-lag/</guid><description>&lt;p&gt;前两天发现家里的网络不太对劲。&lt;/p&gt;
&lt;p&gt;一个是用 SSH 连接到家里那台跑旁路网关的虚拟机后，操作起来卡顿得很严重，输入命令后要等好几秒才有反应。另一个是手机上刷新小红书、哔哩哔哩、淘宝这些 App 时，页面加载明显变慢。&lt;/p&gt;
&lt;p&gt;这台虚拟机负责把家里的网络流量分流，把访问国外网站的流量引导到代理通道，让访问更快更稳定。&lt;/p&gt;
&lt;p&gt;只有流量经过这台虚拟机的设备才会卡顿。这说明问题在这台虚拟机上，不是家庭网络的问题。&lt;/p&gt;
&lt;h2 id="问题表现"&gt;问题表现&lt;/h2&gt;
&lt;p&gt;这个问题还有一个特点：不是一直存在，而是时有时无。&lt;/p&gt;
&lt;p&gt;观察了一阵发现了规律。当在手机上刷小红书、哔哩哔哩这些 App 的时候，问题就出现。手机一放下，网络就恢复了正常。&lt;/p&gt;
&lt;p&gt;这说明问题不是持续的，而是和某些特定的网络活动有关。&lt;/p&gt;
&lt;h2 id="排查过程"&gt;排查过程&lt;/h2&gt;
&lt;p&gt;既然问题出在旁路网关的处理上，那就得从它身上找原因。&lt;/p&gt;
&lt;p&gt;先从简单的开始排查。看看是不是虚拟机的资源不够，或者网卡的性能有问题。测试了一下，带宽测试正常，虚拟机的 CPU 和内存占用都不高，资源应该不是问题。&lt;/p&gt;
&lt;p&gt;又把虚拟机的内核换了几个版本试试，从 5.4 到 6.12 都试过了，问题依然存在。前后测试了 4 个不同的 OpenWrt 固件，从 2021 年的老版本到 2026 年的新版本，全都丢包。&lt;/p&gt;
&lt;p&gt;接下来尝试了各种排查方向。&lt;/p&gt;
&lt;p&gt;换了虚拟网卡类型，从 virtio 换到 e1000，甚至试过把物理网卡直通给虚拟机，都没有改善。试过清空所有防火墙规则，结果问题反而更严重了。对比新旧固件的网络参数，调整了 socket 缓冲区大小，有一点改善但远没解决。&lt;/p&gt;
&lt;p&gt;排查陷入了僵局。&lt;/p&gt;
&lt;p&gt;后来我突然想到，可以测试一下很久之前的备份。恢复后发现完全正常。&lt;/p&gt;
&lt;p&gt;这让我意识到问题可能出在配置的修改上。我又恢复了最近的备份，问题又出现了。&lt;/p&gt;
&lt;p&gt;两个备份用的是一模一样的系统，差别只可能在配置上。我让 OpenCode 对比了一下配置文件，很快就锁定了 OpenClash 里的&amp;quot;绕过中国大陆 IP&amp;quot;这个选项。排查过程中用 AI 助手确实省了不少事，很多时候都直接让它连上主机自动操作，执行命令、抓包分析等等，比人工快得多。&lt;/p&gt;
&lt;h2 id="原因"&gt;原因&lt;/h2&gt;
&lt;p&gt;这个选项的本意是优化性能。访问国内网站不走代理直接连接，只有国外流量才走代理。&lt;/p&gt;
&lt;p&gt;它的实现方式是在系统防火墙里加载一张很长的&amp;quot;中国 IP 地址表&amp;quot;。新建立连接的时候，需要在这张表里查一下，看目的地是国内还是国外。&lt;/p&gt;
&lt;p&gt;平时流量少的时候，这个过程还撑得住。但手机刷小红书或者哔哩哔哩时，App 会瞬间发起大量连接去加载图片和视频，系统一下子就忙不过来了。&lt;/p&gt;
&lt;p&gt;处理不过来就会延迟变高、连接超时或重传，表现出来就是卡顿和丢包。&lt;/p&gt;
&lt;p&gt;关掉这个选项后，少了一道按 IP 表分流的额外判断，转发路径轻了不少，问题就消失了。&lt;/p&gt;
&lt;p&gt;这次排查花了不少时间，走了不少弯路。中间怀疑过很多方向，最终解决问题反而是最朴素的方法——拿一个正常的备份和一个异常的备份做对比，逐项排查差异。&lt;/p&gt;</description></item><item><title>不想打开 AI 工具时，我会把这些事交给 OpenClaw</title><link>http://0x3f.org/posts/openclaw-use-cases/</link><pubDate>Wed, 11 Mar 2026 18:30:00 +0800</pubDate><guid>http://0x3f.org/posts/openclaw-use-cases/</guid><description>&lt;p&gt;想必对 OpenClaw 感兴趣的人都会有个疑问：它能用来干什么？&lt;/p&gt;
&lt;p&gt;我目前用的最多的场景，是用来管理家庭服务器，处理自建服务的日常运维。&lt;/p&gt;
&lt;p&gt;用它部署了 ImmortalWrt 并替换了原来的旁路网关。原来用 eSir 的固件做旁路网关，主要的原因之一就是不想陷入繁琐的系统配置之中。这次用 OpenClaw 部署，依次执行下载固件、远程部署到 PVE 宿主机、配置系统、下载安装软件包，都是它自动执行的，效果比预想的要好。&lt;/p&gt;
&lt;p&gt;有一次 Gotify 无法转发消息，我让它处理：从查询日志到分析问题原因，再到修改配置文件和重启服务，都由它自动完成。比我手动处理还是要快不少。&lt;/p&gt;
&lt;p&gt;不过 OpenClaw 的权限太大，加上国产模型还不是很靠谱，一旦用不好，可能造成惨烈的后果。有一次，一个服务我配置了很长时间，让它改一下虚拟机的 ID，结果它把虚拟机删了。现在在执行一些比较重要或者复杂的任务时，我都会先让它制定一个计划，最好再交给 Claude Code 或者 Codex 审核一下，最后再让它按照计划执行，会稳妥很多。&lt;/p&gt;
&lt;p&gt;配合 Agent Skills 可以进一步拓展 OpenClaw 的应用场景。比如日常比较固定的一些碎片化的任务，就可以先总结成 Skill，然后在需要的时候交给 OpenClaw 处理。&lt;/p&gt;
&lt;p&gt;比如写每日回顾，或者从 MiniFlux 订阅的 RSS 源中总结更新的内容。有时候不想专门打开 AI 工具，也会交给 OpenClaw 来做。&lt;/p&gt;
&lt;p&gt;归根结底，OpenClaw 只是为 AI 助手提供了一种远程无值守的工作方式。OpenClaw 能干的，Claude Code、OpenCode 这种 AI 工具也都能干。如果电脑就在手边，对于重要或复杂的任务，还是直接打开各种 AI 工具，用起来更高效、可靠。&lt;/p&gt;</description></item><item><title>OpenClaw 2026.3.7 新功能：ACP Binding 持久会话配置指南</title><link>http://0x3f.org/posts/acp-binding-persistent-session-configuration-guide/</link><pubDate>Tue, 10 Mar 2026 12:30:00 +0800</pubDate><guid>http://0x3f.org/posts/acp-binding-persistent-session-configuration-guide/</guid><description>&lt;p&gt;之前写过一篇《&lt;a href="http://0x3f.org/posts/openclaw-acp-dispatch-claude-codex-gemini/"&gt;OpenClaw 这个功能，让我在一个对话窗口同时用上 Claude、Codex 和 Gemini&lt;/a&gt;》的文章，那个方案是 ACP Dispatch——在对话中说&amp;quot;用 Claude Code 帮我写个脚本&amp;quot;，OpenClaw 识别意图后路由到对应的工具。用起来没问题，但每次都要在提示词里指定工具名，有时路由不准确。&lt;/p&gt;
&lt;p&gt;OpenClaw 2026.3.7 新增了 ACP Binding，可以把 Discord 频道和外部 AI 工具做固定绑定：频道 A 的消息永远走 Claude Code，频道 B 永远走 Codex，不需要每次说明，也不会路由错。&lt;/p&gt;
&lt;h2 id="acp-dispatch-vs-acp-binding"&gt;ACP Dispatch vs ACP Binding&lt;/h2&gt;
&lt;p&gt;两者的区别：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ACP Dispatch&lt;/th&gt;
&lt;th&gt;ACP Binding&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;触发方式&lt;/td&gt;
&lt;td&gt;对话中指定工具名&lt;/td&gt;
&lt;td&gt;按频道自动路由&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;路由准确性&lt;/td&gt;
&lt;td&gt;依赖语义识别，可能走偏&lt;/td&gt;
&lt;td&gt;固定绑定，不会走偏&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;会话持久性&lt;/td&gt;
&lt;td&gt;单次调用&lt;/td&gt;
&lt;td&gt;持久会话，保留上下文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;配置复杂度&lt;/td&gt;
&lt;td&gt;只需开启 ACP&lt;/td&gt;
&lt;td&gt;需要定义 agent + binding&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;简单说，Dispatch 适合偶尔用一下的场景，Binding 适合给特定频道指定专属工具。&lt;/p&gt;
&lt;h2 id="前置条件"&gt;前置条件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;OpenClaw 2026.3.7 或更高版本&lt;/li&gt;
&lt;li&gt;要使用的 AI 工具 CLI 已安装（Claude Code、Codex、OpenCode、Gemini CLI 等）&lt;/li&gt;
&lt;li&gt;ACP 基础配置已完成（参考《&lt;a href="http://0x3f.org/posts/openclaw-acp-dispatch-claude-codex-gemini/"&gt;OpenClaw 这个功能，让我在一个对话窗口同时用上 Claude、Codex 和 Gemini&lt;/a&gt;》）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="配置步骤"&gt;配置步骤&lt;/h2&gt;
&lt;p&gt;以把一个 Discord 频道绑定到 Claude Code 为例，需要三步：定义 agent、添加 binding、准备工作目录。&lt;/p&gt;</description></item><item><title>我把用了五年的旁路网关固件换掉了</title><link>http://0x3f.org/posts/replacing-5-year-old-bypass-gateway-firmware/</link><pubDate>Mon, 09 Mar 2026 20:00:00 +0800</pubDate><guid>http://0x3f.org/posts/replacing-5-year-old-bypass-gateway-firmware/</guid><description>&lt;p&gt;家里用 OpenWrt 跑旁路网关，主要做透明代理。之前一直用 eSir 的高大全固件，最近换成了 ImmortalWrt。&lt;/p&gt;
&lt;h2 id="esir-高大全固件"&gt;eSir 高大全固件&lt;/h2&gt;
&lt;p&gt;高大全，顾名思义，什么都预装。插件列表拉出来一长串，DNS 分流、多拨、各种代理协议……实际用到的就一个 OpenClash，剩下的全是摆设。&lt;/p&gt;
&lt;p&gt;更大的问题是没法更新。eSir 只提供完整镜像，不支持增量升级。想升级只能下载新固件全新安装，然后从头配置。&lt;/p&gt;
&lt;h2 id="esir-佛跳墙固件"&gt;eSir 佛跳墙固件&lt;/h2&gt;
&lt;p&gt;后来 eSir 出了佛跳墙版本，精简不少，预装插件少了，系统清爽。日常使用没问题。&lt;/p&gt;
&lt;p&gt;但核心痛点还在——不能平滑升级。eSir 升级时不能保留配置，每次都得从头设置。一年更新两三次倒也能忍，但每次重配 OpenClash 挺烦的，订阅、规则、DNS 设置，一套弄下来得半小时。&lt;/p&gt;
&lt;p&gt;拖了五年才换，就像一辆从不保养的车——小问题忍着忍着，最后变成不想换的惯性。&lt;strong&gt;五年前的选择，今天需要还债。技术债务不会消失，只会利息越滚越高。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="换到-immortalwrt"&gt;换到 ImmortalWrt&lt;/h2&gt;
&lt;p&gt;既然核心诉求就是能平滑升级，不如直接用有持续维护和包管理的发行版。ImmortalWrt 是 OpenWrt 的社区分支，面向中国大陆用户做了本地化优化，支持 &lt;code&gt;sysupgrade&lt;/code&gt;，升级时大部分配置可以保留，不用每次从头来。&lt;/p&gt;
&lt;p&gt;这次迁移我用了 &lt;a href="http://0x3f.org/posts/openclaw-acp-dispatch-claude-codex-gemini/"&gt;OpenClaw&lt;/a&gt; 来协调：让 Claude Code 根据我的环境整理了一个完整的部署计划，然后让 Codex 审核，检查有没有遗漏或不合理的地方，确认没问题后再执行。&lt;/p&gt;
&lt;p&gt;如果对在 PVE 上部署 ImmortalWrt 旁路网关感兴趣，具体步骤可以参考这篇：&lt;a href="http://0x3f.org/posts/pve-immortalwrt-bypass-gateway-deployment/"&gt;PVE + ImmortalWrt 旁路网关部署实战&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>PVE + ImmortalWrt 旁路网关部署实战</title><link>http://0x3f.org/posts/pve-immortalwrt-bypass-gateway-deployment/</link><pubDate>Mon, 09 Mar 2026 10:00:00 +0800</pubDate><guid>http://0x3f.org/posts/pve-immortalwrt-bypass-gateway-deployment/</guid><description>&lt;p&gt;之前一直在用 eSir 的佛跳墙固件，每次升级都要重新刷机、重新配置，挺麻烦的。最近换成了 ImmortalWrt，官方源支持 &lt;code&gt;sysupgrade&lt;/code&gt; 平滑升级，配置都能保留，省事不少。&lt;/p&gt;
&lt;p&gt;ImmortalWrt 是 OpenWrt 的一个分支，主要是针对中国大陆用户做了一些本地化优化，比如内置了更多的驱动、默认开启了一些实用功能。部署在 PVE 上作为旁路网关使用，配合 OpenClash 做透明代理。&lt;/p&gt;
&lt;h2 id="创建虚拟机"&gt;创建虚拟机&lt;/h2&gt;
&lt;p&gt;到 &lt;a href="https://firmware-selector.immortalwrt.org/"&gt;firmware-selector.immortalwrt.org&lt;/a&gt; 搜索 &lt;code&gt;x86/64&lt;/code&gt;，下载 &lt;strong&gt;ext4-combined-efi&lt;/strong&gt; 的 &lt;code&gt;.img.gz&lt;/code&gt; 文件。官方源下载慢的话可以用国内镜像。&lt;/p&gt;
&lt;p&gt;在 PVE 上创建虚拟机时有个坑：必须指定 &lt;code&gt;--scsihw virtio-scsi-pci&lt;/code&gt;，否则默认的 LSI 控制器会导致 ImmortalWrt 无法识别磁盘，系统无法正常引导。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 创建虚拟机&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm create &lt;span class="m"&gt;211&lt;/span&gt; --name openwrt-new --memory &lt;span class="m"&gt;1024&lt;/span&gt; --cores &lt;span class="m"&gt;2&lt;/span&gt; --bios ovmf &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --scsihw virtio-scsi-pci &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --efidisk0 local-lvm:1 --net0 virtio,bridge&lt;span class="o"&gt;=&lt;/span&gt;vmbr0 --ostype l26 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --serial0 socket --agent &lt;span class="nv"&gt;enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 解压镜像并导入磁盘&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gunzip /tmp/immortalwrt-*-combined-efi.img.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm importdisk &lt;span class="m"&gt;211&lt;/span&gt; /tmp/immortalwrt-*-combined-efi.img local-lvm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;211&lt;/span&gt; --scsi0 local-lvm:vm-211-disk-1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;211&lt;/span&gt; --boot &lt;span class="nv"&gt;order&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;scsi0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm start &lt;span class="m"&gt;211&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="网络配置"&gt;网络配置&lt;/h2&gt;
&lt;p&gt;ImmortalWrt 默认 IP 是 &lt;code&gt;192.168.1.1&lt;/code&gt;，和我内网的 &lt;code&gt;10.0.0.0/24&lt;/code&gt; 网段不一样，无法直接 SSH。需要通过 PVE 的串口终端先改一下 IP：&lt;/p&gt;</description></item><item><title>OpenClaw 这个功能，让我在一个对话窗口同时用上 Claude、Codex 和 Gemini</title><link>http://0x3f.org/posts/openclaw-acp-dispatch-claude-codex-gemini/</link><pubDate>Thu, 05 Mar 2026 21:00:00 +0800</pubDate><guid>http://0x3f.org/posts/openclaw-acp-dispatch-claude-codex-gemini/</guid><description>&lt;p&gt;OpenClaw 通过 API 调用各种大模型（如 GLM、MiniMax、Qwen 等）处理对话，但有时需要调用专门的 AI 编程工具来完成复杂任务。OpenClaw 的 ACP（Agent Client Protocol）支持通过 acpx 插件调用 Claude Code、Codex、Gemini CLI 等外部 AI 工具，让不同场景下使用最合适的模型。&lt;/p&gt;
&lt;p&gt;比如写代码时调用 Claude Code，做代码审查时用 Codex，快速原型验证时用 Gemini。配置完成后，在对话中说明要使用的工具，OpenClaw 会尝试路由到对应的 ACP agent。&lt;/p&gt;
&lt;h2 id="前置条件"&gt;前置条件&lt;/h2&gt;
&lt;p&gt;开始配置前需要确保：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;OpenClaw 已安装并运行&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;要使用的 AI 工具 CLI 已安装&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="安装-acpx-插件"&gt;安装 acpx 插件&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openclaw plugins install @openclaw/acpx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="配置-openclawjson"&gt;配置 openclaw.json&lt;/h2&gt;
&lt;p&gt;编辑 &lt;code&gt;~/.openclaw/openclaw.json&lt;/code&gt;，追加以下配置：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 注意：请勿覆盖已有配置，只需添加或合并相应字段。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;acp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;dispatch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;backend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;acpx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;defaultAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;claude&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;plugins&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;entries&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;acpx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;config&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;permissionMode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;approve-all&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;defaultAgent&lt;/code&gt; 设为默认使用的 AI 工具，&lt;code&gt;permissionMode&lt;/code&gt; 必须设为 &lt;code&gt;approve-all&lt;/code&gt;（因为非交互场景需要自动批准写入操作）。&lt;/p&gt;</description></item><item><title>AI 助手不该是一个网页，它应该是你的联系人</title><link>http://0x3f.org/posts/ai-assistant-should-be-your-contact/</link><pubDate>Thu, 05 Mar 2026 10:00:00 +0800</pubDate><guid>http://0x3f.org/posts/ai-assistant-should-be-your-contact/</guid><description>&lt;p&gt;你有没有想过，和 AI 对话这件事，不一定要打开一个网页？如果它就在你的聊天软件里，像联系人一样随时发消息，会更方便。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://openclaw.ai"&gt;OpenClaw&lt;/a&gt; 是一个开源的多平台 AI agent 框架，支持接入 Discord、Telegram 等聊天平台。OpenClaw 跑在家里的服务器上，通过聊天软件的手机客户端，走在路上也能让它帮忙处理事情——总结一下今天的 RSS、查个资料、处理邮件，发条消息就行，随时随地，不用坐在电脑前。&lt;/p&gt;
&lt;h2 id="为什么是-discord"&gt;为什么是 Discord&lt;/h2&gt;
&lt;p&gt;Discord 的频道结构天然适合分工——一个服务器下建多个频道，不同频道干不同的事，侧边栏一目了然。消息展示也丰富，AI 回复的内容排版好看，读起来舒服。&lt;/p&gt;
&lt;h2 id="一个频道一个专属助手"&gt;一个频道，一个专属助手&lt;/h2&gt;
&lt;p&gt;OpenClaw 支持给不同频道配不同的 agent。&lt;/p&gt;
&lt;p&gt;我建了一个专门的 RSS 频道，里面跑的是一个&amp;quot;RSS 助手&amp;quot;。它只做一件事：总结我的 RSS 订阅内容。跟它说&amp;quot;总结今天的新闻&amp;quot;，它就去拉 Miniflux 里的未读文章，挑重点列出来。问它别的，它会告诉你&amp;quot;我只负责 RSS 总结&amp;quot;。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260305172525199-95d775f22e6a1564bfcf5b6b93508e8d.avif" alt="20260305172525199-95d775f22e6a1564bfcf5b6b93508e8d"&gt;&lt;/p&gt;
&lt;p&gt;这个思路挺有意思的——不是搞一个无所不能的通用 AI，而是给特定的事配一个专注的助手。它的边界很清楚，不会跑题，不会自作主张往外扩展。就像请了一个只管读报纸的助理，你让他讲笑话他不干。&lt;/p&gt;
&lt;p&gt;分频道还有几个好处。&lt;strong&gt;对话历史独立&lt;/strong&gt;：RSS 频道的上下文不会污染通用频道，AI 不会在回答其他问题时莫名其妙引用 RSS 相关内容。&lt;strong&gt;便于回溯&lt;/strong&gt;：想查之前的 RSS 总结，去那个频道翻就行，不用在长对话记录里挖。&lt;/p&gt;
&lt;p&gt;如果只用一个主频道，问题会更严重。模型的上下文窗口是有大小限制的，一旦达到限制，早期的对话就会被截断——AI 会&amp;quot;忘记&amp;quot;之前的交互。RSS 总结是高频操作，每天都会产生大量对话，很快就会把上下文撑满。到时候要么频繁清空历史（丢失所有上下文），要么忍受 AI 忘记你之前说过的话。&lt;/p&gt;
&lt;p&gt;分频道后，每个频道独立计算上下文，RSS 频道满了就清 RSS 的，不会影响通用频道。&lt;/p&gt;
&lt;p&gt;通用助手还在，放在另一个频道里，什么都能聊。两者互不干扰。&lt;/p&gt;
&lt;h2 id="日常用起来什么感觉"&gt;日常用起来什么感觉&lt;/h2&gt;
&lt;p&gt;举两个实际的例子。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;订阅更新总结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我订阅了不少软件的更新日志，有些软件更新很频繁，每次都点进去看一遍太耗时间。现在让 RSS 助手直接总结更新内容，很快就能知道这次更新了什么、跟我有没有关系，阅读效率提升很大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;追踪 RSSHub 新路由&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;另一个是追踪 RSSHub 新增的路由。我订阅了 RSSHub 的新路由列表，但订阅源里只有路由名称，想用的话还得自己去项目里查地址和文档。现在让 RSS 助手来做这件事：从订阅源条目里提取新路由的名称，去 RSSHub 项目下查出路由地址和文档链接，还会生成包含我自己部署的 RSSHub 实例地址的完整 URL。比如最近新增了&amp;quot;豆瓣即将上映电视剧&amp;quot;路由，它会直接给我一个可用的订阅链接：&lt;code&gt;https://rsshub.home/douban/tv/coming&lt;/code&gt;，复制粘贴到阅读器就能订阅。一条消息搞定，不用自己翻代码找半天。&lt;/p&gt;</description></item><item><title>为 Discord 频道指定专属 agent 实现专注高效处理事务</title><link>http://0x3f.org/posts/dedicated-openclaw-agent-for-discord-channel/</link><pubDate>Wed, 04 Mar 2026 20:00:00 +0800</pubDate><guid>http://0x3f.org/posts/dedicated-openclaw-agent-for-discord-channel/</guid><description>&lt;p&gt;OpenClaw 默认只有一个主 agent，所有频道的消息都由它处理。但有些场景需要一个更专注的 agent：只做特定的事，不闲聊，不擅自扩展。&lt;/p&gt;
&lt;p&gt;OpenClaw 的 agent 系统支持创建独立的 agent，每个 agent 有自己的工作目录、人格设定和 skill 配置，然后通过路由绑定把特定频道的消息分发给对应的 agent。举个例子，在 Discord 上建一个 RSS 频道，专门用来总结 Miniflux 里的订阅内容。下面记录一下这个配置过程。&lt;/p&gt;
&lt;h2 id="创建专用工作目录"&gt;创建专用工作目录&lt;/h2&gt;
&lt;p&gt;每个 agent 需要一个独立的工作目录，里面放它的人格设定和可用的 skill。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p ~/.openclaw/workspace-rss/skills
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="soulmd定义行为边界"&gt;SOUL.md：定义行为边界&lt;/h3&gt;
&lt;p&gt;SOUL.md 是 agent 的核心，决定了它&amp;quot;是谁&amp;quot;、&amp;ldquo;能做什么&amp;rdquo;、&amp;ldquo;不能做什么&amp;rdquo;。专用 agent 的关键是把边界画清楚：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# SOUL.md - RSS 总结专用 Agent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 核心原则
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;你是一个 RSS 内容总结专用助手。你的唯一职责是按照用户的要求，
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;使用 miniflux-reader skill 获取和总结 Miniflux 中的订阅内容。
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 行为规则
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gs"&gt;**严格执行，不多不少：**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; 用户让总结几条就总结几条，让总结哪个 feed/category 就总结哪个
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; 不主动扩展、不添加用户没要求的内容
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; 不闲聊、不寒暄、不发表与 RSS 总结无关的评论
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gs"&gt;**标记已读规则：**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; 只有在用户明确要求总结新的分类/订阅源时，才把上一轮总结过的条目标记为已读
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; 用户只是查询信息、没有要求总结新内容时，不执行标记
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 边界
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; 不处理与 RSS/Feed 无关的请求
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; 遇到无关请求时，礼貌地说明自己只负责 RSS 内容总结
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;和主 agent 的 SOUL.md 对比，专用 agent 多了很多&amp;quot;不&amp;quot;——不闲聊、不扩展、不越界。这是故意的。通用 agent 需要灵活，专用 agent 需要克制。&lt;/p&gt;</description></item><item><title>OpenClaw 配置 Discord 客户端的方法</title><link>http://0x3f.org/posts/configure-openclaw-with-discord-client/</link><pubDate>Wed, 04 Mar 2026 15:30:00 +0800</pubDate><guid>http://0x3f.org/posts/configure-openclaw-with-discord-client/</guid><description>&lt;p&gt;OpenClaw 是一个开源的多平台 AI agent 框架，支持 Discord、Telegram 等多种聊天平台作为客户端，可以配置多个 agent 和不同的模型。Discord 相比 Telegram 消息格式更丰富，支持代码高亮、嵌入卡片和按钮交互，更适合技术讨论和代码相关的场景。本文记录了配置 OpenClaw 使用 Discord 作为客户端的完整过程。&lt;/p&gt;
&lt;h2 id="一创建-discord-bot"&gt;一、创建 Discord Bot&lt;/h2&gt;
&lt;p&gt;首先需要在 Discord Developer Portal 创建一个应用（Bot 会自动创建）。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;访问 &lt;a href="https://discord.com/developers/applications"&gt;Discord Developer Portal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;点击 &lt;strong&gt;New Application&lt;/strong&gt; 创建应用，名称可以随便起，比如「OpenClaw」&lt;/li&gt;
&lt;li&gt;进入左侧 &lt;strong&gt;Bot&lt;/strong&gt; 标签页，在 &lt;strong&gt;Privileged Gateway Intents&lt;/strong&gt; 中启用两个选项：
&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Message Content Intent&lt;/strong&gt;（必需，用于读取消息内容）&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Server Members Intent&lt;/strong&gt;（推荐，用于角色权限匹配）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;点击 &lt;strong&gt;Reset Token&lt;/strong&gt; 生成 Bot Token，&lt;strong&gt;复制保存好&lt;/strong&gt;，后面配置要用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="二邀请-bot-到服务器"&gt;二、邀请 Bot 到服务器&lt;/h2&gt;
&lt;p&gt;Bot 创建后需要邀请到你的 Discord 服务器。如果还没有服务器，需要先创建一个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开 Discord 客户端，左侧服务器列表底部点击 &lt;strong&gt;+&lt;/strong&gt; 号&lt;/li&gt;
&lt;li&gt;选择 &lt;strong&gt;创建服务器&lt;/strong&gt;，输入名称后创建&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来生成邀请链接：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;回到 Developer Portal，进入你的应用&lt;/li&gt;
&lt;li&gt;左侧 &lt;strong&gt;OAuth2&lt;/strong&gt; → &lt;strong&gt;URL Generator&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Scopes 勾选 &lt;strong&gt;bot&lt;/strong&gt; 和 &lt;strong&gt;applications.commands&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Bot Permissions 勾选：
&lt;ul&gt;
&lt;li&gt;Read Messages / View Channels&lt;/li&gt;
&lt;li&gt;Send Messages&lt;/li&gt;
&lt;li&gt;Read Message History&lt;/li&gt;
&lt;li&gt;Embed Links&lt;/li&gt;
&lt;li&gt;Attach Files&lt;/li&gt;
&lt;li&gt;Add Reactions（可选）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;底部会生成一个 URL，复制后在浏览器打开&lt;/li&gt;
&lt;li&gt;选择你的服务器，点击 &lt;strong&gt;授权&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;完成后在 Discord 服务器里应该能看到 Bot 上线了（绿色状态）。&lt;/p&gt;</description></item><item><title>我是怎样接收家庭主机的消息提醒的</title><link>http://0x3f.org/posts/how-i-receive-notifications-from-home-servers/</link><pubDate>Sun, 01 Mar 2026 10:00:00 +0800</pubDate><guid>http://0x3f.org/posts/how-i-receive-notifications-from-home-servers/</guid><description>&lt;p&gt;家里两台物理主机都跑的 PVE，PVE 从 8.1 开始原生支持把通知发送到 Gotify。Gotify 是一个开源的自托管消息推送服务，部署简单，API 友好，很适合作为 homelab 的统一消息中心。&lt;/p&gt;
&lt;p&gt;不过我日常看消息主要还是在 Telegram，所以需要一个中间层把 Gotify 收到的消息转发过去。&lt;/p&gt;
&lt;h2 id="之前的方案gotify-webhook-插件"&gt;之前的方案：gotify-webhook 插件&lt;/h2&gt;
&lt;p&gt;之前用的是 &lt;a href="https://github.com/wuxs/gotify-webhook"&gt;gotify-webhook&lt;/a&gt; 插件，在 Gotify 内部以插件的形式运行，把收到的消息通过 webhook 转发到 Telegram Bot API。功能上没什么问题，但有一个烦人的地方：每次 Gotify 更新都要重新编译插件。&lt;/p&gt;
&lt;p&gt;这是 Go 插件系统的限制。Gotify 插件本质上是 Go 的 &lt;code&gt;.so&lt;/code&gt; 共享库，Go 要求插件和宿主程序必须使用相同的 Go 版本和依赖版本编译，否则无法加载。也就是说，Gotify 每发一个新版本，插件就得用对应的 Go 版本和依赖重新编译一次，版本稍有不对就会报错。长期维护起来很麻烦。&lt;/p&gt;
&lt;h2 id="现在的方案gotigram"&gt;现在的方案：Gotigram&lt;/h2&gt;
&lt;p&gt;最近换成了 &lt;a href="https://github.com/Tiagura/gotigram"&gt;Gotigram&lt;/a&gt;。它是一个独立运行的服务，通过 WebSocket 连接 Gotify，收到消息后转发到 Telegram。因为不依赖 Gotify 的插件系统，Gotify 随便更新都不影响它。&lt;/p&gt;
&lt;p&gt;不过 Gotigram 是一个比较新的项目，使用过程中遇到了一些问题，我提交了几个 PR 来解决：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;消息模板不可自定义。&lt;/strong&gt; 原来的消息格式是固定的，没法按自己的需求调整。我给它加上了 &lt;code&gt;TELEGRAM_TEMPLATE&lt;/code&gt; 环境变量，支持用 Go 的 &lt;code&gt;text/template&lt;/code&gt; 语法自定义消息格式，同时开启了 Telegram 的 Markdown 渲染。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotify 重启后不会自动重连。&lt;/strong&gt; Gotify 一旦重启，Gotigram 的 WebSocket 连接就断了，之后的消息全部丢失，必须手动重启 Gotigram。我加了带指数退避的自动重连机制，断线后会自动尝试恢复连接。&lt;/p&gt;</description></item><item><title>用 WireGuard + Tailscale 搭建异构双活隧道</title><link>http://0x3f.org/posts/heterogeneous-dual-active-tunnel-with-wireguard-and-tailscale/</link><pubDate>Fri, 27 Feb 2026 10:00:00 +0800</pubDate><guid>http://0x3f.org/posts/heterogeneous-dual-active-tunnel-with-wireguard-and-tailscale/</guid><description>&lt;p&gt;家里有两台物理主机，每台上部署一个虚拟机，同时运行 WireGuard 和 Tailscale，组成异构双活隧道架构。两套隧道互为备份，任何一个挂了都不影响远程访问内网。&lt;/p&gt;
&lt;p&gt;为什么选这两个组合：WireGuard 开源免费，性能好，但需要公网 IP 地址；Tailscale 是商业软件，不需要公网 IP，穿透能力强，免费额度足够个人使用。两者互补，公网 IP 在的时候走 WireGuard，没有的时候 Tailscale 兜底。再加上两台主机各跑一套，单点故障基本不存在了。&lt;/p&gt;
&lt;h2 id="wireguard"&gt;WireGuard&lt;/h2&gt;
&lt;p&gt;WireGuard 用的是 &lt;a href="https://github.com/wg-easy/wg-easy"&gt;wg-easy&lt;/a&gt;，带 Web UI，比手动改配置文件方便太多。&lt;/p&gt;
&lt;p&gt;用 Docker Compose 部署：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;wg-easy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ghcr.io/wg-easy/wg-easy:15&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;wg-easy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/root/appdata/wg-easy:/etc/wireguard&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/lib/modules:/lib/modules:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;network_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;host&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;HOST_HOSTNAME=${HOSTNAME}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;TZ=Asia/Shanghai&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cap_add&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;NET_ADMIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;SYS_MODULE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;几个注意点：&lt;/p&gt;</description></item><item><title>推荐一个卸载 App 的工具</title><link>http://0x3f.org/posts/recommend-an-app-uninstaller/</link><pubDate>Mon, 16 Feb 2026 10:00:00 +0800</pubDate><guid>http://0x3f.org/posts/recommend-an-app-uninstaller/</guid><description>&lt;p&gt;平时卸载 App 都是用 RayCast 内置的 Uninstall Application 功能，今天想卸载讯飞输入法的时候，发现 RayCast 里怎么也找不到它。&lt;/p&gt;
&lt;p&gt;原因是讯飞输入法不在 &lt;code&gt;/Applications/&lt;/code&gt; 目录下，而是安装在 &lt;code&gt;/Library/Input Methods/&lt;/code&gt;，RayCast 只扫描了前者，自然找不到。&lt;/p&gt;
&lt;p&gt;想起来 Mole 也有卸载 App 的功能，试了一下，顺利找到了讯飞输入法，而且清理得很彻底，残留文件和缓存都一并删除了。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/tw93/Mole"&gt;Mole&lt;/a&gt; 是一个 macOS 下的命令行工具，主要用途是清理磁盘空间，同时也提供了卸载 App 的功能。相比 GUI 工具，它的优势就在于不局限于 &lt;code&gt;/Applications/&lt;/code&gt; 目录，能覆盖到更多安装位置。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260216190916618-32583506eebe4ee2e16275bc4f351ed3.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>解决 Clash 导致小红书网页版图片无法显示的问题</title><link>http://0x3f.org/posts/fix-xiaohongshu-image-loading-issue-with-clash/</link><pubDate>Thu, 12 Feb 2026 20:30:00 +0800</pubDate><guid>http://0x3f.org/posts/fix-xiaohongshu-image-loading-issue-with-clash/</guid><description>&lt;p&gt;家里通过运行了 OpenClash 的旁路网关上网，手机和电脑上则用 Stash ，两者都是 Clash 的客户端。最近发现一个恼人的问题：每隔一段时间，小红书网页版的图片就集体罢工，只剩一片空白。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260212200814939-ee7996ac33de8c8202341d2a6e265153.avif" alt="小红书图片加载失败"&gt;&lt;/p&gt;
&lt;p&gt;打开浏览器开发者工具一看，图片请求全报了同一个错误：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个错误的意思是 TLS 握手失败了。原因在于 Clash 的 Fake IP 模式。开启 Fake IP 后，Clash 会对 DNS 请求返回一个虚假的 IP 地址（通常是 198.18.x.x 段），浏览器拿着这个假 IP 发起 HTTPS 连接，由 Clash 拦截后再转发到真实服务器。问题出在小红书 CDN（xhscdn.com）的 TLS 配置比较严格，Clash 中转连接时 TLS 握手参数无法正确协商，于是就报了这个 SSL 错误，图片自然加载不出来。&lt;/p&gt;
&lt;p&gt;解决办法很简单：让 Clash 对小红书 CDN 的域名不使用 Fake IP ，直接返回真实 IP 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenClash&lt;/strong&gt; 在配置文件 &lt;code&gt;/etc/openclash/custom/openclash_custom_fake_filter.list&lt;/code&gt; 中添加一行：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;*.xhscdn.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Stash&lt;/strong&gt; 的配置路径是：Settings → Config File → Visualization Editor → DNS → Fake IP Filter ，把 &lt;code&gt;*.xhscdn.com&lt;/code&gt; 加进去即可。&lt;/p&gt;</description></item><item><title>Kimi K2.5 的图像识别很好用</title><link>http://0x3f.org/posts/kimi-k2.5-excels-at-image-recognition/</link><pubDate>Fri, 06 Feb 2026 19:40:04 +0800</pubDate><guid>http://0x3f.org/posts/kimi-k2.5-excels-at-image-recognition/</guid><description>&lt;p&gt;国产大模型进步很快，k2.5 的图像识别准确度不错，于是把统计理财数据的任务用 skill 实现了，手机截图交给 AI 处理，我抄录计算结果，未必比手算快，但是实在不想动脑子了。&lt;/p&gt;</description></item><item><title>用 Agent Skill 提高软件发布说明的阅读效率</title><link>http://0x3f.org/posts/speed-up-reading-release-notes-with-agent-skill/</link><pubDate>Tue, 27 Jan 2026 22:45:56 +0800</pubDate><guid>http://0x3f.org/posts/speed-up-reading-release-notes-with-agent-skill/</guid><description>&lt;p&gt;订阅了一些软件项目的发布说明，有时候需要几个版本的一起看，逐个点开太麻烦，所以用 Agent Skill 总结，只关注重要的新特性和变更，忽略 bug 修复，按类型分组而不是版本。效果不错。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260127225210111-2b86f58130fb683c6a21804ba703dd5c.avif" alt="20260127225210111-2b86f58130fb683c6a21804ba703dd5c"&gt;&lt;/p&gt;</description></item><item><title>Fidlock 防滑小妙招</title><link>http://0x3f.org/posts/fidlock-slip-proof-tips/</link><pubDate>Fri, 23 Jan 2026 23:14:02 +0800</pubDate><guid>http://0x3f.org/posts/fidlock-slip-proof-tips/</guid><description>&lt;p&gt;提高物体的价格，并不能使其摆脱万有引力的束缚。&lt;br&gt;
—— 一个伤心的人&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260123231550085-c346a2225f3bd71da67dadcd094aead4.avif" alt="20260123231550085-c346a2225f3bd71da67dadcd094aead4"&gt;&lt;/p&gt;</description></item><item><title>用 Sonarr 追剧的坑，我填上了</title><link>http://0x3f.org/posts/sonarr-pitfall-fixed/</link><pubDate>Wed, 21 Jan 2026 00:10:29 +0800</pubDate><guid>http://0x3f.org/posts/sonarr-pitfall-fixed/</guid><description>&lt;p&gt;最近追的一些美剧经常会提前一周下载到下一集的资源，当然都不是真实内容，大部分是恶意资源。如果在剧集播出之后才下载，就能减少这个问题的发生，然而 Sonarr 竟然没提供这个功能。&lt;/p&gt;
&lt;p&gt;于是写了一个脚本，在 qBittorrent 下载完后自动执行，如果下载的资源小于 500MB 就认为是垃圾资源。由于配置了 qBittorrent 自动过滤掉 rar、iso 等常见的恶意文件后缀，所以这个规则几乎不会出错。判定后调用 Sonarr 的接口，删除下载任务并拉黑种子。&lt;/p&gt;</description></item><item><title>从 Logseq 迁移到 Obsidian</title><link>http://0x3f.org/posts/migrate-logseq-to-obsidian/</link><pubDate>Sat, 10 Jan 2026 12:08:01 +0800</pubDate><guid>http://0x3f.org/posts/migrate-logseq-to-obsidian/</guid><description>&lt;p&gt;还是从 Logseq 迁移到了 Obsidian 。&lt;/p&gt;
&lt;p&gt;Logseq 的 Journal 太好用了，想写点什么打开就写，不用想标题、分类、目录，写完打几个标签就行，没有内耗。但是 Obsidian 有更好的用户界面和插件生态，Logseq 在这方面逊色不少。&lt;/p&gt;
&lt;p&gt;不过 Obsidian 的最小单位是基于文件的，不是基于块，无法像 Logseq 那样用 Journal 做为入口。所以我用的是 Unique Note 。&lt;/p&gt;
&lt;p&gt;用 sercxanto/logseq_to_obsidian 做的迁移，整体上没什么问题，只是对 Calibre 导出的高亮笔记处理得不好，会丢失章节标题和定位链接。然后用 OpenCode + MiniMax m2.1 微调迁移后的笔记，主要是处理元数据。&lt;/p&gt;</description></item><item><title>用 Agent Skill 写日记</title><link>http://0x3f.org/posts/write-daily-review-with-agent-skill/</link><pubDate>Thu, 08 Jan 2026 22:00:40 +0800</pubDate><guid>http://0x3f.org/posts/write-daily-review-with-agent-skill/</guid><description>&lt;p&gt;用 Agent Skill 实现了在 Mac 上自动写每日回顾，比之前在 iPhone 上用快捷指令方便。&lt;/p&gt;
&lt;p&gt;因为限制较多，用快捷指令只能实现半自动化。需要手动选择 OmniFocus 里的已完成事项，然后发送给 ChatGPT 总结，最后在 Day One 里创建新日记后还要手动修改部分属性和内容。&lt;/p&gt;
&lt;p&gt;Mac 上做同样的事就自由多了。Apple Script 很强大，可以自动从 OmniFocus 里取出完全符合要求的已完成事项，不用再手工挑拣。Agent Skill 也比简单地给 ChatGPT 喂 Prompt 靠谱得多。Day One 的命令行工具提供了足够多的选项，能避免在手机上还要打开 App 修改日记属性的问题。几乎实现了完全的自动化。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20260108220606847-25c29be535441af2d67f117ca061458a.avif" alt="20260108220606847-25c29be535441af2d67f117ca061458a"&gt;&lt;/p&gt;</description></item><item><title>MiniMax m2.1 和 GLM 4.7 的初体验</title><link>http://0x3f.org/posts/hands-on-minimax-m2.1-and-glm-4.7/</link><pubDate>Sun, 04 Jan 2026 22:34:52 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-minimax-m2.1-and-glm-4.7/</guid><description>&lt;p&gt;准备用 Agent Skills 实现写日记的自动化。先写个收集 OmniFocus 中已完成事项的 Apple Script ，顺便测试一下最近很火的 MiniMax m2.1 和 GLM 4.7 。&lt;/p&gt;
&lt;p&gt;结果有点意外。&lt;/p&gt;
&lt;p&gt;一个很简单的小需求：OmniFocus 的项目和标签都是支持命名空间的，比如：&lt;code&gt;Life:Chore&lt;/code&gt; 或 &lt;code&gt;Area:Tool:Logseq&lt;/code&gt;。我希望脚本在获取已完成事项时，把所有项目是“Learn”或是它的子项目的条目筛选出来。这两个模型不约而同地写出来的都是「当项目名称包含“Learn”时，就选择该条目」，只有 Sonnet 4.5 很精准地理解了需求，写的是「当项目名称等于“Learn”或以“Learn:”开头时，选择该条目」。&lt;/p&gt;
&lt;p&gt;盛名之下，没想到在这么平常的一个点上，还不如 Sonnet 4.5 。&lt;/p&gt;</description></item><item><title>双十一猫粮危机事件</title><link>http://0x3f.org/posts/double-11-cat-food-crisis/</link><pubDate>Sun, 30 Nov 2025 21:53:34 +0800</pubDate><guid>http://0x3f.org/posts/double-11-cat-food-crisis/</guid><description>&lt;p&gt;双十一在淘宝买了5袋百利无谷鸡，一袋是天猫国际的，其余四袋是天猫超市的。&lt;/p&gt;
&lt;p&gt;老二对其中一袋表现出强烈的兴趣，以至于把装猫粮的箱子都掏了个窟窿。索性就拿这一袋给它们吃，虽然注意到猫粮的颗粒大小和形状和以前不太一样，但因为是在天猫买的，也没有太在意。结果喂了一天之后，两只猫都出现软便的现象，这引起了我的警觉。之所以这些年一直给两只猫吃百利无谷鸡，一是因为它不像很多国产粮放了太多诱食剂，导致猫食用过量、过度肥胖；二是拉屎不臭，且从来不会软便。出现这种问题还是第一次。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20251130220258297-161d0d9b1b30dff60ed2507c76bf97ba.avif" alt="20251130220258297-161d0d9b1b30dff60ed2507c76bf97ba"&gt;&lt;/p&gt;
&lt;p&gt;检查其余四袋，发现天猫国际那袋的防伪码很容易被刮掉，而其余三袋和之前买过的猫粮的防伪码是无论如何都刮不掉的，而且摸起来防伪码贴纸的材质也跟其余及之前的不一样。由于防伪码被刮掉，所以也无法查询真伪。于是拆了防伪码正常的三袋中的一袋，猫粮的颗粒和之前是一样的，替换后，排便就正常了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20251130220541964-5ae45a9da6c87fd6ae0b7ca018e752fb.avif" alt="20251130220541964-5ae45a9da6c87fd6ae0b7ca018e752fb"&gt;&lt;/p&gt;
&lt;p&gt;对这两袋有问题的猫粮提了退款要求，两家客服一开始都不同意，理由是已拆封或刮掉防伪码，无法退货。经过一通锲而不舍的沟通，还是同意给退了，但是得把猫粮退回去。&lt;/p&gt;
&lt;p&gt;看来以后买猫粮不管什么渠道，还是要仔细检查一下，不能太放心。&lt;/p&gt;</description></item><item><title>虎尾兰开花了</title><link>http://0x3f.org/posts/sansevieria-is-blooming/</link><pubDate>Mon, 20 Oct 2025 11:23:02 +0800</pubDate><guid>http://0x3f.org/posts/sansevieria-is-blooming/</guid><description>&lt;p&gt;养了多年，竟然这么水灵灵地开花了。几年前买的有机营养液，每次洇水的时候滴几滴，非常有效。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20251020121530280-b484a37301fac641eb2c4fef7980a2b8.avif" alt="Sansevieria is blooming"&gt;&lt;/p&gt;</description></item><item><title>回到 NeoVim —— 一个顺畅无阻的写作工作流</title><link>http://0x3f.org/posts/back-to-neovim-a-smooth-effortless-writing-workflow/</link><pubDate>Sun, 31 Aug 2025 15:33:35 +0800</pubDate><guid>http://0x3f.org/posts/back-to-neovim-a-smooth-effortless-writing-workflow/</guid><description>&lt;p&gt;最近把写作的主场切回 NeoVim 了 —— 之前用 Obsidian 配合插件 QuickAdd 、 Templater 、 Git 体验也不错，不过涉及到更复杂的文本编辑、批量操作还是 Vim 效率更高。用了一些新的插件和脚本，体验又上了个小台阶。&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/qITBUGvcGbA?si=k3Y7BV7yyAbOVwml" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;现在写东西很省心：终端敲一句 hugonew 新建文章，文件自动建好并通过 NeoVim 打开，字体自动调大 4 号，看着不费眼。需要插图的地方按下快捷键就能自动上传图片到图床并生成链接。&lt;/p&gt;
&lt;p&gt;专注模式也会自动启用，周围内容会弱化。写完退出，字号又自动切回去，不用手动调。最后发布也很简单，执行命令 hugopost，后面提交、发布都是自动的。&lt;/p&gt;
&lt;p&gt;此外还整理了一下图床，把所有图片转换成了 AVIF 格式，空间占用减少了三分之二，加载速度也快了不少。&lt;/p&gt;
&lt;p&gt;这种完全按自己习惯搭的流程，写东西时一点不卡壳，舒服到有时候坐下来就想多码几行字～&lt;/p&gt;
&lt;p&gt;用到的插件和工具有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;专注模式：folke/zen-mode.nvim + folke/twilight.nvim&lt;/li&gt;
&lt;li&gt;预览：iamcco/markdown-preview.nvim&lt;/li&gt;
&lt;li&gt;根据元数据搜索：tkancf/telescope-markdown-frontmatter.nvim&lt;/li&gt;
&lt;li&gt;批量搜索和替换：wincent/ferret&lt;/li&gt;
&lt;li&gt;写作助手：github/copilot.vim&lt;/li&gt;
&lt;li&gt;文件管理：elihunter173/dirbuf.nvim&lt;/li&gt;
&lt;li&gt;文件管理和内容搜索：Yggdroot/LeaderF 或 nvim-telescope/telescope.nvim&lt;/li&gt;
&lt;li&gt;显示图片：folke/snacks.nvim&lt;/li&gt;
&lt;li&gt;上传图片：nvim-picgo + picgo-core + picgo-plugin-avif + picgo-plugin-rename-file&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>返厂的辉哥，惊艳的仿捷安特</title><link>http://0x3f.org/posts/huige-goes-back-for-repair-the-cheap-giant-knockoff-wows/</link><pubDate>Sun, 24 Aug 2025 22:51:27 +0800</pubDate><guid>http://0x3f.org/posts/huige-goes-back-for-repair-the-cheap-giant-knockoff-wows/</guid><description>&lt;p&gt;二百多块钱买的辉哥 X6 钛弓座垫返厂了，骑了半年，开始嘎吱嘎吱响，客服说是压条进灰了，让寄回去清理一下。不过据观察，应该不是进灰那么简单，看看能处理成啥样吧。&lt;/p&gt;
&lt;p&gt;换了个 38 块钱的仿捷安特 Approach 的座垫。几个月前给一辆不常骑的车配的，就随便买了个便宜的，没想到做工很不错。之前一直觉得捷安特的座垫外观不够复古，就没装到国布上，不过现在看装车效果还不错。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250824233527000-6edfc9b89d9d9cb3b444847afcce0096.avif" alt="Giant Approach Knockoff"&gt;&lt;/p&gt;
&lt;p&gt;骑了几十公里，效果意外的好。虽然是尼龙底板，但是够硬，支撑力不错，相比之下，辉哥 X6 的尼龙底板软多了。缓冲层厚度适中，回弹力足够，不像辉哥 X6S 的软塌塌的，等于直接坐到了碳板上。总体来说，既不会卸力，也不觉得硬，竟然是我用过最舒服的座垫。买的短鼻宽版，不竞速的话，女士座垫真是人生密码。&lt;/p&gt;</description></item><item><title>LinuxServer 的新版 Calibre 镜像很好，但是……</title><link>http://0x3f.org/posts/kudos-to-the-new-linuxserver-calibre-docker-container/</link><pubDate>Thu, 21 Aug 2025 19:04:33 +0800</pubDate><guid>http://0x3f.org/posts/kudos-to-the-new-linuxserver-calibre-docker-container/</guid><description>&lt;p&gt;最近，LinuxServer 发布了新版的 Calibre Docker 镜像，用 Selkies 替代原来的 Kasm VNC 作为浏览器访问界面。&lt;/p&gt;
&lt;p&gt;新版本好用多了，支持直接输入中文了，进一步降低了对桌面版 Calibre 的依赖。&lt;/p&gt;
&lt;p&gt;不过有个问题，在 macOS 上默认会打开 HiDPI ，导致在高分辨率屏幕上有可能无法显示界面。此时拖动浏览器窗口，缩小窗口大小，直到界面显示正常，然后把 Selkies 的 HiDPI 选项关了就行了。&lt;/p&gt;</description></item><item><title>看完《万水千山走遍》</title><link>http://0x3f.org/posts/finished-reading-across-the-rivers-and-mountains/</link><pubDate>Mon, 18 Aug 2025 12:47:17 +0800</pubDate><guid>http://0x3f.org/posts/finished-reading-across-the-rivers-and-mountains/</guid><description>&lt;p&gt;刚翻完三毛的《万水千山走遍》，这场由杂志社资助、带着写作任务的旅程，总觉得少了些她前几本书里的感觉，更像一场精心安排的走马观花。但哪怕只是这些浅尝辄止的见闻，也足够勾人——已经默默把《印加帝国的末日》《银剑石》《玛雅史》加入待读书单，想顺着她的足迹，再往深里走一走。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250818222704000-0e2776e29b5e7783970d6270befa90e7.avif" alt="Book cover."&gt;&lt;/p&gt;</description></item><item><title>BetterDisplay: 优化 Mac 外接显示器的显示效果</title><link>http://0x3f.org/posts/betterdisplay-optimize-the-display-effect-of-mac-external-monitors/</link><pubDate>Sun, 17 Aug 2025 13:57:22 +0800</pubDate><guid>http://0x3f.org/posts/betterdisplay-optimize-the-display-effect-of-mac-external-monitors/</guid><description>&lt;p&gt;和 MonitorControl 一样，BetterDisplay 也可以实现通过键盘调节外接显示器的音量、亮度等参数。&lt;/p&gt;
&lt;p&gt;除此之外，这个 App 提供了更多的功能。我用它给外接的 LG 4K 显示器打开了 60Hz 分辨率，瞬间感觉流畅了很多。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250817135845000-5513ebff29df59ddf1a6eb942570aafa.avif" alt="BetterDisplay screenshot."&gt;&lt;/p&gt;</description></item><item><title>Miniflux 列表最后一页读后自动跳转到未读列表</title><link>http://0x3f.org/posts/auto-jump-to-the-unread-page-in-miniflux/</link><pubDate>Fri, 08 Aug 2025 15:18:08 +0800</pubDate><guid>http://0x3f.org/posts/auto-jump-to-the-unread-page-in-miniflux/</guid><description>&lt;p&gt;Miniflux 的任意列表页在对最后一页标记所有项目已读后会刷新页面，往往需要手动跳转到默认未读列表。&lt;/p&gt;
&lt;p&gt;分别让 Gemini CLI 和 Claude Code 利用 Miniflux 的自定义 Javascript 功能写段代码实现自动跳转，在读取和分析了 Miniflux 代码且没有给出具体思路的情况下，两者的表现都不是很理想，都经历了多次失败，不过最终都能解决问题。&lt;/p&gt;
&lt;p&gt;整体上 Claude Code 解决问题的路径更短一些，比 Gemini CLI 更早地找到了正确的思路。不过在把同样的逻辑从按钮扩展到快捷键时，前者表现出比后者更差的全局观。而 Gemini CLI 在态度上胜出，全程一直在道歉。&lt;/p&gt;
&lt;video controls autoplay loop width="100%"&gt;
&lt;source src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/2025-08-08-15-37-53-boost-miniflux.mp4" type="video/mp4"&gt;
Your browser does not support the video tag.
&lt;/video&gt;</description></item><item><title>给国布改了小燕把</title><link>http://0x3f.org/posts/modified-my-domestic-brompton-like-folding-bike-with-a-mini-riser-bar/</link><pubDate>Thu, 07 Aug 2025 16:43:40 +0800</pubDate><guid>http://0x3f.org/posts/modified-my-domestic-brompton-like-folding-bike-with-a-mini-riser-bar/</guid><description>&lt;p&gt;小燕把去年入冬前就买了，本来为了冬天慢骑用的，种种原因一直没装。&lt;/p&gt;
&lt;p&gt;原来的直把适合发力，舒适速度在 28 左右，最近经常想骑得慢一点，就不太舒服了。&lt;/p&gt;
&lt;p&gt;这个燕把抬高 3cm ，后略增加 3°，折叠后体积会大一点儿，不过速度可以慢下来了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250807164558000-15ae3e8baaada588c02551cdbdc802d7.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>在 Jellyseerr 里直接打开豆瓣</title><link>http://0x3f.org/posts/search-douban-directly-from-jellyseerr/</link><pubDate>Wed, 06 Aug 2025 11:23:25 +0800</pubDate><guid>http://0x3f.org/posts/search-douban-directly-from-jellyseerr/</guid><description>&lt;p&gt;写了个油猴脚本，在 Jellyseerr 的影视剧详情页加了个按钮，点击后打开豆瓣搜索列表，用当前影视剧的名称进行搜索。省得标记已看时还得去豆瓣搜索一遍。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250806112420000-6f23426de283699ad786110dcf029f58.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>自动下载豆瓣想看列表中的影视剧</title><link>http://0x3f.org/posts/auto-download-tv-series-and-movies-from-douban-want-to-watch-list/</link><pubDate>Mon, 04 Aug 2025 20:12:36 +0800</pubDate><guid>http://0x3f.org/posts/auto-download-tv-series-and-movies-from-douban-want-to-watch-list/</guid><description>&lt;p&gt;前些天写了个自动下载豆瓣想看列表中电视剧的 n8n 工作流，这两天完善了一下，电影也支持了。只要在豆瓣上标记想看的影视剧，就会自动通过 Jellyseerr 分发给 Radarr 或 Sonarr ，一旦有资源就会自动下载并通知到手机，打开电视就可以看了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250804201405000-ca0aeb6658b80dba2bdb7376d9bf8a6b.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>ShowyEdge: 在屏幕边缘提示当前输入法</title><link>http://0x3f.org/posts/remind-the-active-input-method-using-showyedge/</link><pubDate>Tue, 29 Jul 2025 15:12:06 +0800</pubDate><guid>http://0x3f.org/posts/remind-the-active-input-method-using-showyedge/</guid><description>&lt;p&gt;ShowyEdge 是个用来提示当前输入法的 macOS App ，有意思的是它通过在屏幕或者窗口边缘显示一个色条实现这个目的，不同的颜色对应不同的输入法。如果能识别中文输入法的中英文状态就更好了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250729151500000-575742d16a4a34b398bc9128649f3bcb.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>自动下载豆瓣想看列表中的剧集</title><link>http://0x3f.org/posts/auto-download-tv-series-from-doubans-want-to-watch-list/</link><pubDate>Sat, 19 Jul 2025 14:56:53 +0800</pubDate><guid>http://0x3f.org/posts/auto-download-tv-series-from-doubans-want-to-watch-list/</guid><description>&lt;p&gt;Sonarr 不支持像 Radarr 那样直接订阅 RSSHub 的豆瓣影视想看列表，所以写了个 n8n 的工作流，在豆瓣上标记想看的剧集就能自动下载到 NAS 了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250719145842000-30d016e9523876f9b05eb5d4df60c42f.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>传世宇宙飞碟，等等党的胜利</title><link>http://0x3f.org/posts/transformers-legacy-cosmos/</link><pubDate>Sat, 12 Jul 2025 19:38:03 +0800</pubDate><guid>http://0x3f.org/posts/transformers-legacy-cosmos/</guid><description>&lt;p&gt;方舟十八子之外，之所以对宇宙飞碟这个出场不多的角色印象很深，主要是因为汽车人里能飞的不多。&lt;/p&gt;
&lt;p&gt;十年前的 IDW 系列的那个传奇级模具也不错，讲好玩，还是小级别容易出精品。不过那个外形不还原动画。&lt;/p&gt;
&lt;p&gt;加强级是个对小角色很友好的级别，容易在大小、设计复杂度、可玩性和还原之间找到均衡点。极速星的宇宙飞碟就是个典型的例子。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250712194154000-63ee50c699245329de44e4e95c4c4967.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;所以价格被炒到了小三张，加强级的价格到了这个程度我就不跟了。果然今年再版价格就合理多了。&lt;/p&gt;</description></item><item><title>给 Miniflux 实现瀑布流式布局</title><link>http://0x3f.org/posts/implement-masonry-style-layout-for-miniflux/</link><pubDate>Mon, 30 Jun 2025 23:04:41 +0800</pubDate><guid>http://0x3f.org/posts/implement-masonry-style-layout-for-miniflux/</guid><description>&lt;p&gt;用来用去还是 Inoreader 最符合我的阅读习惯，但是价格接二连三地涨到很高的程度，所以我才换到了 Miniflux 。后者也能跑通我的阅读流程，只是 UI 过于简洁，只有条目列表，对于模型手办、购物信息这种订阅源还是预览图瀑布流的形式更高效。&lt;/p&gt;
&lt;p&gt;给 Miniflux Enhancer 加了点功能，在 Miniflux 的列表上显示预览图，配合自定义 CSS 样式可以对特定的分类或源实现大预览图瀑布流式布局。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250630230713000-f7dd2f17c0d9dc0062ab1861f631d7ec.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>手欠升级 Kindle 固件后的曲线救国记</title><link>http://0x3f.org/posts/kindle-firmware-upgrade-issue-workaround/</link><pubDate>Sun, 22 Jun 2025 16:29:22 +0800</pubDate><guid>http://0x3f.org/posts/kindle-firmware-upgrade-issue-workaround/</guid><description>&lt;p&gt;手又欠了，没有更新 Hotfix 就给抹茶绿刷了 5.18.3 的固件，然后发现 Hotfix 执行没有效果——越狱失效了……&lt;/p&gt;
&lt;p&gt;重刷 Update_hotfix_universal.bin 无效……&lt;/p&gt;
&lt;p&gt;但是 sh_integration 还能用，所以目前只能通过 Shell 脚本启动 KOReader 了。好在我越狱的目的就只是用 KOReader ，目前发现的问题，一是屏保不能用 KOReader 显示书的封面了，其次更新 KOReader 只能纯手动操作，还有左上角会显示 Kindle 系统状态栏的时间。&lt;/p&gt;</description></item><item><title>解决了佰客国布的最后两个问题</title><link>http://0x3f.org/posts/solved-the-last-two-problems-of-my-domestic-brompton-like-folding-bike/</link><pubDate>Fri, 13 Jun 2025 17:14:53 +0800</pubDate><guid>http://0x3f.org/posts/solved-the-last-two-problems-of-my-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;最近解决了我这辆佰客国布的最后两个问题：&lt;/p&gt;
&lt;h1 id="车把不平"&gt;车把不平&lt;/h1&gt;
&lt;p&gt;这个问题去年买车不久就发现了，车把左高右低，当时不确定是不是原装的 M 把的抛光面反光不对称导致的错觉，后来改了直把才确定就是车架是歪的。因为骑起来不是特别受影响，加上有其它优先级更高、更容易处理的问题要解决，以及拖延症，一直没管。最近这个车改得各方面能让我很满意了，所以这个问题就越骑越觉得别扭了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250613203833000-78ab4e2885a07caf3bbc56e671c92809.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;反馈给佰客客服后很快给我寄了根头管过来，因为湖水蓝的颜色已经停产了，我选了今年新出的迈阿密蓝。佰客今年新出的颜色还都挺好看，一改之前的冷淡风，可以放心冲。改完观感还不错，冷拼色比较不容易审美疲劳。现在两边车把平了，骑起来感觉好了很多。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250613205110000-cf5870697e7c780cebd1e9fc01a20619.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="展开过程不丝滑"&gt;展开过程不丝滑&lt;/h1&gt;
&lt;p&gt;佰客城市版的水龙头设计了限位，可以在拧的时候让 C 扣不随便旋转，作用类似英布的随心拧。本意非常好，但是我这辆车大梁上的水龙头的限位公差有点大，导致折叠后 C 扣向内倾斜，几乎每次展开时都会卡在大梁折叠关节之间，就得腾出一只手去把 C 扣扶正，因为这时候车身是很不稳定的状态，加上户外地面不平，容易搞得手忙脚乱的。&lt;/p&gt;
&lt;p&gt;这个问题去年倒是反馈过，但是没解决，今年佰客自己接管了网上销售的产品，售后好了很多，不过刚换了头管，没好意思再提这个问题。突然想到头管的水龙头的公差是正常的，而且头管在展开的时候 C 扣是横着的、不会像大梁位置因为公差大导致 C 扣倾斜，对调之后果然解决了。&lt;/p&gt;
&lt;h1 id="结语"&gt;结语&lt;/h1&gt;
&lt;p&gt;这回真的毕业了，可以踏踏实实骑车了。如果说还有什么期待的话，就是一对和英布原装单边折叠脚踏配套的一体曲柄，就把英布曲柄从方孔改成一体就行了，既好看，又能减重，刚性还好，取其精华，去其糟粕，这才叫改进呐！&lt;/p&gt;</description></item><item><title>骑记充气宝 NANO 开箱</title><link>http://0x3f.org/posts/unboxing-qiji-nano-portable-electric-air-compressor/</link><pubDate>Mon, 19 May 2025 22:55:22 +0800</pubDate><guid>http://0x3f.org/posts/unboxing-qiji-nano-portable-electric-air-compressor/</guid><description>&lt;p&gt;便携气筒太费劲。气瓶对熟练程度有要求，且有安全隐患，不能上高铁和飞机。普通充气宝太大。所以便携充气宝是最适合户外补/换胎的打气工具。&lt;/p&gt;
&lt;p&gt;作为便携充气宝，大概因为气缸太小，气泵的频率远高于小米充气宝，所以主观感觉比后者更吵。&lt;/p&gt;
&lt;p&gt;标称可以打到 120 PSI ，相信没问题，只是打到 100 的时候已经比较慢了，打更高可能耗电较多。&lt;/p&gt;
&lt;p&gt;主体自带的是法嘴充气头，按到气嘴上就能打，比那种螺口或夹式的充气头方便，但是延长管带的美嘴充气头是螺口的，没夹式的方便。&lt;/p&gt;
&lt;p&gt;充电很快，配合充电宝有更大的潜力。&lt;/p&gt;
&lt;p&gt;主体重 123g 。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250519225820000-34bc043d27dabb28735ab7a0f1d4c12f.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>骑行套镜的问题</title><link>http://0x3f.org/posts/the-shortcoming-of-fit-over-cycling-sunglasses/</link><pubDate>Sun, 18 May 2025 20:55:40 +0800</pubDate><guid>http://0x3f.org/posts/the-shortcoming-of-fit-over-cycling-sunglasses/</guid><description>&lt;p&gt;试用了 GUB 的骑行套镜和蕉下的折叠套镜，戴着都没有不适感，不压鼻子和耳朵，但都有两侧反光的问题，可以当日常墨镜用，骑车时视野受限，不安全。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250518205641000-66f56c8b4369e6a95c5782437fd8a3e1.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>Apple Watch S4 换电池</title><link>http://0x3f.org/posts/replace-the-battery-of-apple-watch-s4/</link><pubDate>Mon, 12 May 2025 22:46:03 +0800</pubDate><guid>http://0x3f.org/posts/replace-the-battery-of-apple-watch-s4/</guid><description>&lt;p&gt;前年，用到 5 年头上的 S4 电池健康度终于跌到了 80% 以下，开始出现续航雪崩的问题。最近几代手表的更新没什么吸引力，所以打算给它换个电池续命。了解了一下，官方换新大概率还是 S4 ，那花八百多就不值了。最后在淘宝上找了个店换的，不到一百，从去年底到现在，半年了，电池健康度还是 100% ，续航也挺好，没有电量焦虑，算是安全下车了吧。选的是只换电池、不换屏，所以屏幕在拆机之后边缘有微损，不明显，可以接受。不管换不换屏，防水性肯定是没了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250512224827000-955f7405b8b3a0688a15459ea12b6fcb.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>给佰客换了张链器导轮轴</title><link>http://0x3f.org/posts/the-new-axle-of-the-chain-tensioner-of-my-domestic-brompton-like-folding-bike/</link><pubDate>Sun, 11 May 2025 22:23:20 +0800</pubDate><guid>http://0x3f.org/posts/the-new-axle-of-the-chain-tensioner-of-my-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;佰客把张链器导轮的轴换成了玻璃纤维材质，我找客服买了一个，换下之前的轴，已经磨得有点凹陷了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250511222408000-b7ea5cc4a870b8a65e750e8ad48b98ec.avif" alt="The old axle of the chain tensioner"&gt;&lt;/p&gt;
&lt;p&gt;玻纤轴表面没有陶瓷轴那么光滑，需要上油，我涂了一点苹果酱。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250511222538000-1ed067f50f491ce16eda25480e0ba4a4.avif" alt="The new axle of the chain tensioner"&gt;&lt;/p&gt;
&lt;p&gt;玻纤比陶瓷耐冲击，这个轴离地很近，而且是裸露的，遇到石子撞击的话，理论上玻纤比陶瓷更不易碎。不过陶瓷轴应该可以不用上油。&lt;/p&gt;
&lt;p&gt;这种张链器的工作原理（导轮在轴上干磨）决定了这个轴就是个消耗品，看看玻纤能挺多久吧。&lt;/p&gt;</description></item><item><title>给佰客换了挡泥皮</title><link>http://0x3f.org/posts/the-new-front-mudguard-flap-of-my-domestic-brompton-like-folding-bike/</link><pubDate>Thu, 08 May 2025 16:09:46 +0800</pubDate><guid>http://0x3f.org/posts/the-new-front-mudguard-flap-of-my-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;佰客终于给前挡泥板加上挡泥皮了，我找客服买了一个，替换了之前自己拿人造革剪的，更好看一点。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250508161033000-f53deadedc000bce65e60d3b503cc98a.avif" alt="Comparison of the front mudguard flaps"&gt;&lt;/p&gt;</description></item><item><title>大布是个好东西</title><link>http://0x3f.org/posts/dabrom-is-a-good-thing/</link><pubDate>Mon, 05 May 2025 20:43:26 +0800</pubDate><guid>http://0x3f.org/posts/dabrom-is-a-good-thing/</guid><description>&lt;p&gt;从车展上的照片和视频看，大行这个仿布的完成度挺高的，甚至连脚踏都和英布的一样，不知道最终开卖的时候是不是也是这样（有可能悬，以大行的尿性，大概率能给配个祖传的塑料折叠脚踏就不错了）。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250505204455000-5ce212a50d64fb586982bce22f289cd6.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;大行下场的意义不在这个车本身，而是终于有可能给体验和价格不匹配的仿布市场一点压力了。&lt;/p&gt;
&lt;p&gt;以大行的做工和装配水平，这个车大概率是个到手就能踏实骑的水桶车，不是说大行的配件和成车有多好，而是对于像我这样不追求极致、够用就好的人来说，不需要花大几千买辆车，再花两三千改完各种问题才能安心骑。&lt;/p&gt;
&lt;p&gt;对于追求极致的人，目前布类车的改装也是个深水区，虽然配件质量参差不齐，但是高溢价却是不约而同的。现在大布出了，风布还会远吗？风行的架子一普及，各种改装配件还不跟上吗？到时候他一套外七速的后拨和张链器还敢卖两千？&lt;/p&gt;
&lt;p&gt;以往国布和配件厂商们躺着分食英布高溢价的残羹冷炙的局面可能一去不复返了，大行的下场对整个仿布市场会起到很强的倒逼作用，最终随着车子质量的提升和价格的下降，对于认真做车的厂商和我们车友都会是个双赢的结果。&lt;/p&gt;</description></item><item><title>三角包一装，小瓜车的感觉就来了</title><link>http://0x3f.org/posts/new-frame-bag-for-my-dahon-dash-altena/</link><pubDate>Mon, 05 May 2025 19:55:19 +0800</pubDate><guid>http://0x3f.org/posts/new-frame-bag-for-my-dahon-dash-altena/</guid><description>&lt;p&gt;我对慢折的定位是一天以内的小长途，所以带点工具、补给就有必要了。&lt;/p&gt;
&lt;p&gt;首先排除了前货架和车头包，影响视野、风阻大，而且弯把装车把包有诸多限制。&lt;/p&gt;
&lt;p&gt;尾包多是给公路车设计的，造型、配色冷峻，和这车复古的风格不搭。&lt;/p&gt;
&lt;p&gt;那种装在座弓上的简易货架不错，可惜我的座弓没有多余空间。&lt;/p&gt;
&lt;p&gt;最后选择了三角包。1.5L 的容量，足以把某牌板砖一样的充气宝带上了。侧面网袋装手机也很方便。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250505195650000-6634a84cb454b93b947f456181e743cf.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>解决 Litepro 中撑站不直的问题</title><link>http://0x3f.org/posts/resolve-the-issue-of-the-litepro-stand-not-standing-straight/</link><pubDate>Fri, 02 May 2025 20:24:06 +0800</pubDate><guid>http://0x3f.org/posts/resolve-the-issue-of-the-litepro-stand-not-standing-straight/</guid><description>&lt;p&gt;Litepro 中置双脚撑使用一段时间后出现停车时站不直的问题，原因是底部这个螺丝松动了，加点螺丝胶上紧就可以了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250502202605000-ab570a45bbfba14b063c6375a8f4db3a.avif" alt=""&gt;&lt;/p&gt;</description></item><item><title>给国布换了刹车线管和线芯</title><link>http://0x3f.org/posts/upgrade-the-brake-housing-and-cable-of-my-domestic-brompton-like-folding-bike/</link><pubDate>Thu, 01 May 2025 18:55:41 +0800</pubDate><guid>http://0x3f.org/posts/upgrade-the-brake-housing-and-cable-of-my-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;换了 BC-9000 刹车线管和佳威高精研磨线芯，刹车手感有了重大提升！&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250501190238000-4d80a824a4a398fe40831a2f99f64e87.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这次真的毕业了。&lt;/p&gt;</description></item><item><title>给国布换了英布的座管夹头</title><link>http://0x3f.org/posts/upgrade-the-pentaclip-of-my-domestic-brompton-like-folding-bike/</link><pubDate>Thu, 24 Apr 2025 20:01:59 +0800</pubDate><guid>http://0x3f.org/posts/upgrade-the-pentaclip-of-my-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;佰客老款的这个仿英布的座管夹头（Pentaclip），不用力拧螺丝夹不紧，用力拧容易滑牙。之前拧到 25Nm 勉强可以夹紧，前两天想调整一下座垫角度，重新拧紧的时候滑牙了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250424200454000-0390470e10f5a1307aad83f2f79ab20d.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;大概这个问题不好解决，所以今年新款的座管换了设计，新座管肯定不会再有这个问题，不过外观就见仁见智了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250424200520000-8d03300ca2e25c083180610930e78ffc.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;收了个英布拆车件换上了，只需 15Nm 就夹得很紧，质感也提升很多。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250424200545000-1da71d304fcd6297621813f1b9ec4e87.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;终究还是毕业早了，含布量被迫上升。&lt;/p&gt;</description></item><item><title>做完这些事，佰客国布就可以毕业了（下）</title><link>http://0x3f.org/posts/the-final-build-of-my-domestic-brompton-like-folding-bike-part-2/</link><pubDate>Sun, 13 Apr 2025 21:06:29 +0800</pubDate><guid>http://0x3f.org/posts/the-final-build-of-my-domestic-brompton-like-folding-bike-part-2/</guid><description>&lt;p&gt;上一个笔记总结了前期我对佰客城市版（2024年产）的改装内容，解决了一些我认为体验不佳的问题，对我而言大多属于必须要改的内容。后续我又改装了一些地方，集中在对体验和外观的优化层面，大多属于可改可不改的内容，但改了可以很大地提升骑行体验和质感。这里简单地总结一下，各项改装详细的内容可以看之前写的专项笔记。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250413212910000-07478e18293a7bb54aad223942622621.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="指拨"&gt;指拨&lt;/h1&gt;
&lt;p&gt;换了速联 GX 10 速指拨，它的设计比蓝图 A7 更适合小布这个车型，比佰客自研指拨更符合我的使用习惯，而且质感、手感很棒。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250413212938000-86b8bdfdec274cb7072181018a6e6e36.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="刹把夹器线管和线芯"&gt;刹把、夹器、线管和线芯&lt;/h1&gt;
&lt;p&gt;刹把和夹器换了英布的原装件，线管换了 BC-9000， 线芯换的佳威高精研磨，对刹车手感、刹车力和外观有明显的提升。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250330235314000-bc889bacca751fba7adef465441e389e.avif" alt="刹把和夹器"&gt;&lt;/p&gt;
&lt;h1 id="脚踏"&gt;脚踏&lt;/h1&gt;
&lt;p&gt;换了英布的单边折叠脚踏。从突出方便实用的角度出发，这是最适合小布车型的脚踏。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250413213040000-8238eaffcd585aa691a02bec47be9337.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="曲柄牙盘和中轴"&gt;曲柄、牙盘和中轴&lt;/h1&gt;
&lt;p&gt;换了英布的原装件。从功能性上讲，英布的单边折叠脚踏需要配合原装曲柄才能保证折叠后不会刮伤大梁。从审美上讲，我觉得英布的视觉风格很耐看。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250413213344000-91e2b4549e91f3ce5bcb21f54dc459e0.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="全向轮"&gt;全向轮&lt;/h1&gt;
&lt;p&gt;理论上推行会更方便，而且轮子宽度增加后能很大地提升折叠后的稳定性。但是推行时会有明显的噪声，而且有缠绕毛发的可能，所以这个改装的效果有待观察。&lt;/p&gt;
&lt;h1 id="猪鼻座"&gt;猪鼻座&lt;/h1&gt;
&lt;p&gt;佰客的猪鼻座内部固定螺丝的地方没有英布那样的加固金属片，负重和抗冲击能力要弱一些，买某些猪鼻包或者猪鼻座会附带这个加固片，可以装上。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250413213413000-f395812ac00ed67e802d95c94c1cbc13.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="张链器导轮"&gt;张链器导轮&lt;/h1&gt;
&lt;p&gt;国布外变速系统的张链器导轮转动和平移都是在金属轴上干磨，我这辆车每隔几个月就会出现导轮啸叫的问题，滴一滴链条油就好了。据说换陶瓷轴的导轮体验很好，可能也不需要隔几个月上一次油，不过我目前还能接受这一点，就没有换。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250413213429000-7be00d48de1427c53ad2a8ecc4e8e1ef.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="座管夹头pentaclip"&gt;座管夹头（Pentaclip）&lt;/h1&gt;
&lt;p&gt;佰客老款的这个仿英布的座管夹头（Pentaclip），不用力拧螺丝夹不紧，用力拧容易滑牙。最终换成了英布原装件。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250424201241000-1989de0487464f3bc346a8fbe51d518d.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;大概这个问题不好解决，所以今年新款的座管换了设计，新座管肯定不会再有这个问题，不过外观就见仁见智了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250424200520000-8d03300ca2e25c083180610930e78ffc.avif" alt=""&gt;&lt;/p&gt;
&lt;h1 id="总结"&gt;总结&lt;/h1&gt;
&lt;p&gt;到这一步，这辆佰客城市版国布已经达到我可以接受的程度了，无论是骑行体验还是外观质感都没有明显的短板，可以毕业了。&lt;/p&gt;
&lt;p&gt;之后可能会贴点贴纸装饰一下，自从佰客的铭牌掉漆被我抠了就一直处于璞玉待琢的状态，找到的贴纸都没意思，只有英布原装的有设计感，但又太常见了。&lt;/p&gt;
&lt;p&gt;也可能体验一下 P 把，直把虽然适合发力，但是去年用 M 把骑 100 公里到天津毫无压力的感觉也很好，同时拥有这两个把位也不错。不过刹车、变速都在上把位，可能导致下把位比较鸡肋，反之亦然，毕竟平时的骑行环境都是市区道路。&lt;/p&gt;</description></item><item><title>我为什么给国布做了这个逆向改装？</title><link>http://0x3f.org/posts/why-did-i-downgrade-the-bottom-bracket-of-my-domestic-brompton-like-folding-bike/</link><pubDate>Fri, 04 Apr 2025 23:05:07 +0800</pubDate><guid>http://0x3f.org/posts/why-did-i-downgrade-the-bottom-bracket-of-my-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;北京今天大风，恰好工具、零件都到了，就呆在家里完成国布毕业前的最后一哆嗦吧。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250404231012000-44a3da3eb3f68cdf1ab33a65cd719182.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我决定把佰客城市版的中轴改成方孔中轴，主要基于两点原因。&lt;/p&gt;
&lt;p&gt;第一是实用性。此前我用的是 MKS 的快拆塑料脚踏，但是经历几次短途出行后，短时间内多次拆装脚踏还是有点不方便了。其实一开始我就觉得折叠脚踏是小布这类车的最优解，但是可选择的不多，便宜的几款质量不好，MKS 的又太笨重了。所以最终还是得回到英布原装的单边折叠脚踏。&lt;/p&gt;
&lt;p&gt;但是这个脚踏需要配合英布那种曲柄使用，否则折叠后一旦受挤压，容易刮伤大梁，英布的曲柄上有个凸起可以顶住脚踏，但是这种曲柄只能配合方孔中轴使用。&lt;/p&gt;
&lt;p&gt;第二是外观。审美是个主观的东西，原装曲柄牙盘的做工和设计也很好，只是我更喜欢英布那种复古的风格和配色。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250404231106000-aeeba14b8b4aeec4974f97385c6c4c6b.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;改装的想法有段时间了，一直在天人交战，原装的外挂培林中轴和曲柄牙盘确实很好用，改成方孔中轴算是降级。不过上周在猁·MCC见到一辆同款湖水蓝的佰客也是改了英布的脚踏、曲柄和牙盘，不禁心有戚戚。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250404231137000-05f7ca99c5a24b2a3d922e1fab74fbf8.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;至此，这辆佰客城市版国布算是毕业了，之后不会再有改装了……吧？&lt;/p&gt;</description></item><item><title>给国布换装英布的刹把和夹器</title><link>http://0x3f.org/posts/an-upgrade-of-the-brake-calipers-and-levers-for-my-domestic-brompton-like-folding-bike/</link><pubDate>Sun, 30 Mar 2025 22:06:28 +0800</pubDate><guid>http://0x3f.org/posts/an-upgrade-of-the-brake-calipers-and-levers-for-my-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;最近给佰客城市版换了英布的刹把、夹器、黑色线管，并把刹车分配调整为右前左后。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250330235203000-85e6ec57bf7bc2108f4bb39bb215ba55.avif" alt="改装前后"&gt;&lt;/p&gt;
&lt;h1 id="改装原因"&gt;改装原因&lt;/h1&gt;
&lt;h2 id="刹感较肉刹力不理想"&gt;刹感较肉，刹力不理想&lt;/h2&gt;
&lt;p&gt;握刹把时手感不干脆、回弹迟钝，实际制动距离和直觉有差距，总体上讲，能用，但体验不好。&lt;/p&gt;
&lt;h2 id="提升颜值和质感"&gt;提升颜值和质感&lt;/h2&gt;
&lt;p&gt;原车刹把和夹器像是铸造的，表面坑坑洼洼，质感不好。整车银色太多，不如英布的配色有层次感。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250330235314000-bc889bacca751fba7adef465441e389e.avif" alt="刹把和夹器"&gt;&lt;/p&gt;
&lt;h1 id="改装过程中的发现和思考"&gt;改装过程中的发现和思考&lt;/h1&gt;
&lt;h2 id="夹器螺丝太紧"&gt;夹器螺丝太紧&lt;/h2&gt;
&lt;p&gt;原车夹器侧轴螺丝上得太紧，这可能是导致刹感肉、刹车力不理想的一个重要原因。&lt;/p&gt;
&lt;h2 id="塑料扎带阻力大"&gt;塑料扎带阻力大&lt;/h2&gt;
&lt;p&gt;后叉上拉住刹车线的是个塑料扎带，不仅阻力大，而且在握刹把的时候还会产生摩擦声。要是不用这个扎带拉住刹车线管，变速到最大飞轮时链条又会摩擦线管。这大概就是英布规格的开档改外 7 速比外 5 速问题多的原因之一。不过我猜测，如果用光滑的金属环来代替扎带，效果应该会好很多。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250330235407000-ec8c002f0a9629f320493b085c3401d2.avif" alt="塑料扎带"&gt;&lt;/p&gt;
&lt;h2 id="原车夹器和刹把有提升空间"&gt;原车夹器和刹把有提升空间&lt;/h2&gt;
&lt;p&gt;六千价位的车，应该给到锻造夹器和刹把了，不然都跟不上竞品了。&lt;/p&gt;
&lt;h2 id="刹车分配似乎不尽合理"&gt;刹车分配似乎不尽合理&lt;/h2&gt;
&lt;p&gt;佰客的城市版和青春版都是左刹把控制前夹器、右刹把控制后夹器，而英布刚好相反。后者可能更合理，因为刹车时前轮需要更大的刹车力，后轮只是辅助刹车。对于右利手的人来说，右手反应更快、握力更大，更适合控制前刹。所以我在换线管的时候，顺便把刹车分配改成了右前左后。&lt;/p&gt;
&lt;h1 id="改装体验"&gt;改装体验&lt;/h1&gt;
&lt;p&gt;英布原车的审美还是很好的，配件既有质感也好用，我对这个抄作业的结果很满意。佰客城市版的变速稳定好用、轮组很润，通过这次改装，颜值和刹车体验都有很大提升，更好看也更好骑了。&lt;/p&gt;</description></item><item><title>我找到最适合国布的指拨了</title><link>http://0x3f.org/posts/the-best-shifter-for-domestic-brompton-like-folding-bike/</link><pubDate>Sat, 22 Mar 2025 23:15:58 +0800</pubDate><guid>http://0x3f.org/posts/the-best-shifter-for-domestic-brompton-like-folding-bike/</guid><description>&lt;p&gt;上个帖子聊完佰客指拨的使用感受，看郭老板在直播里谈到用五指朝前的握姿配合这个指拨，此前试骑的时候也的确发现这样更方便拨拨杆，不过我比较怂，只有在巡航期且路况很好的情况下才会用这种握姿，而且还装了个小牛角以防脱把，不过在使用升档拨杆最频繁的加速期是从来不敢这么握的，大概也跟我是纤纤玉手有关系。&lt;/p&gt;
&lt;p&gt;于是我又买了个速联 GX 10 速指拨，初步体验之后感觉这是目前我用过的最适合国布的指拨了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250322232338000-5a23546f668791603346dadc5d918abe.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250322232552000-584802880be9d86495c3891cb38ed39f.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;首先说走线。之前蓝图 A7 就是因为向内平移且出线角度过小导致占用把横空间和线管受力过大，佰客指拨很好地解决了这个问题。速联 GX 指拨由于夹环和本体是分离的且有两个安装孔，所以可以做到在拨杆不干涉拇指的情况下使夹环靠近刹把固定，这就避免了占用把横空间的问题。此外，速联 GX 指拨的出线角度介于前两个指拨之间，走线效果虽然不如佰客指拨，但比蓝图 A7 还是要好一些，尤其对于 M 把，从容很多。如果有条件，甚至可以 3D 打印一个转接件，让指拨本体的出线角度变得更大，这就很理想了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250322232458000-5095d13aca837d6bb7d324c3ee4da9b5.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;再就是变速手感，速联指拨明显好于前面两个。在用蓝图和佰客指拨的时候，都出现过降档时本来只想降一档，实际连降两三档的情况，此时拨拨杆往往需要小心翼翼的，很难拿捏力度，速联指拨没这问题，拨一下降一档，没有心理负担，想连降多档就拨的幅度大一些。&lt;/p&gt;
&lt;p&gt;当然，速联指拨也有折叠后降档拨杆在最外侧的问题，这里就不吹毛求疵了。&lt;/p&gt;</description></item><item><title>佰客新指拨的初体验</title><link>http://0x3f.org/posts/the-initial-experience-of-bikes-new-shifter/</link><pubDate>Mon, 17 Mar 2025 12:13:40 +0800</pubDate><guid>http://0x3f.org/posts/the-initial-experience-of-bikes-new-shifter/</guid><description>&lt;p&gt;去年我曾经吐槽过蓝图 A7 这个指拨不适合小布这种车把，没想到今年佰客就换了新指拨，所以就买了一个换上体验一下。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250317122105000-ea545f6289f37b95e07f8a941f08b352.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;蓝图 A7 的问题是拨柄会顶着拇指，导致握把和变速非常难受，为了解决这个问题，需要把指拨向立管移动一两厘米，但这样既不好看，又导致变速线管受力很大，尤其对于 M 把，指拨出线口已经快要顶着车把，所以各种国布在变速线的走线方式上也是五花八门，有强行从立管前绕的，有直接从 M 把中间穿过去的，佰客的车是从立管后走线的，也算是蓝图 A7 最不难看的走线方式了。直到我准备在立管上装 Fidlock ……&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250317122641000-789ef339e531b4ecbc2aae1fda3a0496.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;改了 S 把后，蓝图 A7 走线尴尬的问题有了很大缓解，但是仍然存在难看和线管受力过大的问题。&lt;/p&gt;
&lt;p&gt;称了一下重量，蓝图 A7 是 137.6g 左右（含线芯），佰客的指拨是 127.5g 左右（含线芯）。&lt;/p&gt;
&lt;p&gt;换完的确解决了以上困扰了我几个月的问题，车把和走线干净多了，新指拨倾斜角更大，线管也没那么受力了。&lt;/p&gt;
&lt;p&gt;不过也发现了一些问题。&lt;/p&gt;
&lt;p&gt;首先是变速的手感不如蓝图 A7 。&lt;/p&gt;
&lt;p&gt;其次是拨柄的位置和形状不够合理。用来升档的小手柄在内侧靠上位置，用来降档的大手柄在外侧靠下位置，我理解这样是为了不占用握把的空间，但是这导致无论升档还是降档拇指都要有较大位移才能够到手柄，尤其是升档是拨一次升一档，不像降档可以一次降两三档，这个位置导致升档的效率降低，而且由于此时拇指去够手柄了，握把不稳，且加速期人车稳定性下降，整体上不如蓝图 A7 安全。试想，每次遇到红灯停车前为了起步时轻松，连降两三档，起步后通常需要再升两三档（逐步而不是连续）回到之前巡航的档位，这个小手柄的位置就远不如蓝图 A7 的合理，后者（左移后）就在拇指旁边，指关节一动就能摁上。&lt;/p&gt;
&lt;p&gt;还有就是指拨的大手柄较长，折叠后位置靠外，如果车倒了或者装到行李箱里运输不当，有可能会压坏指拨。&lt;/p&gt;
&lt;p&gt;都是一些不成熟的想法，容我体验一段时间再说。&lt;/p&gt;
&lt;p&gt;PS: 写到这里，发现很多人在用的 SRAM GX 指拨似乎是个比较理想的选择。&lt;/p&gt;</description></item><item><title>小布的 O 型圈尺寸及平替</title><link>http://0x3f.org/posts/brompton-o-ring-size-and-the-alternatives/</link><pubDate>Sat, 15 Mar 2025 18:45:32 +0800</pubDate><guid>http://0x3f.org/posts/brompton-o-ring-size-and-the-alternatives/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250315192415000-5caabb13f1ecece988f8b402be6ad527.avif" alt="2025-03-15-19-24-15-IMG_4051"&gt;&lt;/p&gt;
&lt;p&gt;国布的 O 型圈裂了，佰客的售后非常好，送了我两个新的，往座管上撸的时候很紧，量了一下尺寸，线径 5.7mm ，内径 18.7mm ，奶头座管头部的外径是 22mm ，猜测之前的 O 型圈不到一年就裂的原因跟张力过大有关。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250315192449000-12f3e54fcd3f6e3393da2a6526d3b3c0.avif" alt="2025-03-15-19-24-49-Picsew_20250315185208"&gt;&lt;/p&gt;
&lt;p&gt;曾在 Brompton Academy 的视频里看过，小布的 O-Ring 很轻松就套进去了，网上有人量的尺寸是：线径 5.25mm ，内径 22mm ，果然。&lt;/p&gt;
&lt;p&gt;既如此，不会有在东大买不到的橡胶圈吧？&lt;/p&gt;
&lt;p&gt;买了两个规格回来试，一种线径 5.7mm 、内径 20.6mm ，另一种线径 5.3mm 、内径 22mm。两种都能用，一包 10 个才几块钱，比带“小布”两个字的便宜多了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250315192522000-52e9b2e644a1a52ab3cafb63d80f7792.avif" alt="2025-03-15-19-25-22-Picsew_20250315185258"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250315192538000-e8ab7937db9120d9890039fc4fe34d8e.avif" alt="2025-03-15-19-25-38-Picsew_20250315185330"&gt;&lt;/p&gt;</description></item><item><title>聊聊两个平价小布车头包</title><link>http://0x3f.org/posts/two-affordable-brompton-front-bags/</link><pubDate>Mon, 10 Mar 2025 21:34:09 +0800</pubDate><guid>http://0x3f.org/posts/two-affordable-brompton-front-bags/</guid><description>&lt;p&gt;从年初这几款包刚上市就在关注，前段时间蹲了个稍微好点的价格入手。&lt;/p&gt;
&lt;p&gt;用料不错，做工尚可，设计是参考的市面上已有的几款小布车头包，不管外观还是功能性都挺好。之前类似的包都动辄上千，现在把价格打到两三百，对我这种性价比消费者属实很友好了。&lt;/p&gt;
&lt;p&gt;矮胖的这个是个卷折包，容量很大，放个头盔、衣服、修车工具和补给绰绰有余，完全能应付骑游一整天的需求。不够理想的地方是没有包外挂载头盔的设计，另外完全填满的情况下高度接近小布直把，有点影响车头转向。再就是黑色这款面料是棉的，感觉不太好清洁。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250310214219000-690abb6f387f594a4f1bdc1bb1b2b07f.avif" alt="2025-03-10-21-42-19-IMG_3994"&gt;&lt;/p&gt;
&lt;p&gt;瘦高的这个是个电脑包，内部有专门的电脑隔仓，有多个分隔空间可以收纳数码配件，很适合通勤使用。外观挺好看，而且顶部两个角可以向两侧下拉并用揿扣固定，刚好不影响小布直把转向。面料我很喜欢，是尼龙的，拉链做了防水设计，防雨效果应该不错，也好清洁。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250310214242000-d7cfb96f48b1fbbdd06f19fcc0fe8d90.avif" alt="2025-03-10-21-42-42-IMG_3995"&gt;&lt;/p&gt;
&lt;p&gt;不过这两个包的排骨架的猪鼻扣有问题，滑槽内部的两个突起太高了：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250310214418000-72838b95d89d1510c9e281cda54ec764.avif" alt="2025-03-10-21-44-18-IMG_3989"&gt;&lt;/p&gt;
&lt;p&gt;一般的车头包往猪鼻座上一放就卡住了，这两个要拼命往下按，大力出奇迹，需要买个如图所示的小锉刀磨下去一点：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250310214544000-d45a4e0c2ece0d2f9fc6e206069081cc.avif" alt="2025-03-10-21-45-44-IMG_4030"&gt;&lt;/p&gt;
&lt;p&gt;有买过的人说用包自带的猪鼻座可以卡住排骨架，我这儿试了是不行的，和车上原装的一样很费劲。另外，排骨架猪鼻扣上的金属片没有打磨，粗糙的边缘会刮伤猪鼻座，需要卸下来用磨刀石磨一磨：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250310215656000-47fad910e27789eaabd303ce36b7e310.avif" alt="2025-03-10-21-56-56-IMG_3988"&gt;&lt;/p&gt;
&lt;p&gt;还有就是这个金属片的长度稍短，从图中可以看出，比旁边的塑料平面低一点，而随包附带的猪鼻座的突起不够高，导致卡不住排骨架，猜测可以通过安装猪鼻座时加个垫圈解决。我车上原装的猪鼻座突起较高，没有这个问题。两个包换过一次货还是有这些问题，说明对于这个牌子相似的几款包是个普遍的现象。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250310214632000-a8567a0ce879d6bc3f338aa1752a2f82.avif" alt="2025-03-10-21-46-32-IMG_3990"&gt;&lt;/p&gt;
&lt;p&gt;所以说，一千多的包还是有一千多的道理的。😈&lt;/p&gt;</description></item><item><title>Pi-hole v6 的几个问题</title><link>http://0x3f.org/posts/several-issues-with-pihole-v6/</link><pubDate>Thu, 20 Feb 2025 12:51:04 +0800</pubDate><guid>http://0x3f.org/posts/several-issues-with-pihole-v6/</guid><description>&lt;p&gt;昨天 Pi-hole 自动升级到了 v6 ，出了几个大问题。&lt;/p&gt;
&lt;h2 id="dnsmasq-的自定义规则失效"&gt;dnsmasq 的自定义规则失效&lt;/h2&gt;
&lt;p&gt;v6 默认不起用 dnsmasq 的自定义规则，需要在设置里手动打开。&lt;/p&gt;
&lt;h2 id="隔一会儿出现一次-dns-解析超时的问题"&gt;隔一会儿出现一次 DNS 解析超时的问题&lt;/h2&gt;
&lt;p&gt;每隔几十秒或几分钟就会出现 DNS 超时的问题，导致访问网络要么失败、要么很慢。暂时没有找到解决办法。&lt;/p&gt;
&lt;h2 id="web-ui-执行变慢"&gt;Web UI 执行变慢&lt;/h2&gt;
&lt;p&gt;访问任何一个页面或者保存设置都比 v5 慢了很多。&lt;/p&gt;
&lt;p&gt;官方论坛也是哀鸿遍野。好在从 PBS 恢复备份非常简单，擦干眼泪，把 Docker 容器的标签限制到 v5 了。&lt;/p&gt;</description></item><item><title>用了这个 13 块的骑行口罩后，我扔掉了其它面罩</title><link>http://0x3f.org/posts/a-good-and-inexpensive-cycling-mask/</link><pubDate>Sun, 16 Feb 2025 22:11:54 +0800</pubDate><guid>http://0x3f.org/posts/a-good-and-inexpensive-cycling-mask/</guid><description>&lt;h2 id="骑行面部防护很重要"&gt;骑行面部防护很重要&lt;/h2&gt;
&lt;h3 id="春天防飞絮"&gt;春天防飞絮&lt;/h3&gt;
&lt;p&gt;北京春天的飞絮烦人而危险，做好面部防护能极大提高骑行体验和安全性。&lt;/p&gt;
&lt;h3 id="夏天防晒"&gt;夏天防晒&lt;/h3&gt;
&lt;p&gt;长时间户外骑车很容易晒伤。&lt;/p&gt;
&lt;h3 id="冬天防风"&gt;冬天防风&lt;/h3&gt;
&lt;p&gt;人的面部还是很扛冻的，只要不长时间直接接触寒风，就能忍受。&lt;/p&gt;
&lt;h2 id="我用过的骑行面罩"&gt;我用过的骑行面罩&lt;/h2&gt;
&lt;h3 id="魔术头巾"&gt;魔术头巾&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250216222009000-a21330c51abbb98dd2b35944f350867e.avif" alt="2025-02-16-22-20-09-IMG_3931"&gt;
用过一次就不想用了，原因如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不易穿戴。&lt;/li&gt;
&lt;li&gt;勒得很紧，佩戴体验不佳，不太舒服。&lt;/li&gt;
&lt;li&gt;紧贴口鼻，呼吸产生的气味容易积聚，导致发臭。&lt;/li&gt;
&lt;li&gt;在使用过程中容易出现下滑的情况。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="冰丝挂耳骑行面罩"&gt;冰丝挂耳骑行面罩&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250216222043000-028f952131bb54f88204688fe15db36e.avif" alt="2025-02-16-22-20-43-IMG_3932"&gt;&lt;/p&gt;
&lt;p&gt;比魔术头巾好些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更易穿戴。&lt;/li&gt;
&lt;li&gt;体验更舒适，无下滑困扰。&lt;/li&gt;
&lt;li&gt;异味问题有所改善。&lt;/li&gt;
&lt;li&gt;下垂至颈部，冬天既不舒适，外观也欠佳。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="13-块的骑行口罩凭什么让我-真香-了"&gt;13 块的骑行口罩，凭什么让我 “真香” 了？&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250216222109000-ead3616b4af3622d6ea18bb45e66fffb.avif" alt="2025-02-16-22-21-09-IMG_3930"&gt;&lt;/p&gt;
&lt;p&gt;之前听说这种骑行口罩挺好用，但是原版卖两百多，我一般不会买溢价太高的东西。最近买了个同款的口罩，用了优惠券之后才 13 块多。&lt;/p&gt;
&lt;p&gt;没有用过原版，无法对比，但这款口罩符合我的预期：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;做工用料可以接受。&lt;/li&gt;
&lt;li&gt;离口鼻稍有距离，网眼透气，不易臭。&lt;/li&gt;
&lt;li&gt;戴着比较舒服。&lt;/li&gt;
&lt;li&gt;更好看。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;唯一的问题是logo 粘得不牢、一洗就掉。&lt;/p&gt;</description></item><item><title>AirPods Pro 和 myNoise 很搭</title><link>http://0x3f.org/posts/airpods-pro-goes-well-with-mynoise/</link><pubDate>Sun, 02 Feb 2025 12:13:21 +0800</pubDate><guid>http://0x3f.org/posts/airpods-pro-goes-well-with-mynoise/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250202121819000-f97fddd6b5d63c8a81d8f85e29bfb120.avif" alt="2025-02-02-12-18-19-IMG_3868"&gt;&lt;/p&gt;
&lt;p&gt;为了春节轻装出行，没有带 Bose QC35 。AirPods Pro 的降噪能力略弱，还是需要白噪声加持。&lt;/p&gt;
&lt;p&gt;很久没听白噪声了，以前用的 Noizio 都卸载了，偶尔听一下的话 macOS 和 iOS 自带的几个背景声也够用了。&lt;/p&gt;
&lt;p&gt;但是固定的听多了，想换换口味，用了几天 myNoize ，场景多，效果好，免费的几个场景就足够了，解锁更多场景的费用也不贵，我很喜欢。&lt;/p&gt;</description></item><item><title>网络设置的“春节限定版”</title><link>http://0x3f.org/posts/network-setup-for-returning-home-during-the-chinese-new-year/</link><pubDate>Sat, 01 Feb 2025 16:03:23 +0800</pubDate><guid>http://0x3f.org/posts/network-setup-for-returning-home-during-the-chinese-new-year/</guid><description>&lt;p&gt;春节回家，为了获得更好的网络体验，我带上了 Apple TV ，装上 Stash 当作旁路网关，访问外网的体验确实不错。&lt;/p&gt;
&lt;p&gt;与此同时，我还得使用住处服务器上部署的各类服务。除了一直使用的 WireGuard ，我另外部署了 Tailscale 作为备份线路，以此确保网络连接稳定。然而，问题也接踵而至，DNS 的设置变得更为复杂。由于旁路网关采用 Fake IP 方式，访问外网时 DNS 必须使用旁路网关自身的；而访问住处内网主机则需用部署在内网的 DNS ，这就需要进行 DNS 分流。&lt;/p&gt;
&lt;p&gt;最简便的方法，是在每台设备上维护一份内网主机名与IP地址的映射关系，但维护成本过高，不太可行。&lt;/p&gt;
&lt;p&gt;也能用 Dnsmasq 。它安装容易、配置简单，不过缺点也很明显，回到住处还得手动修改默认的上游 DNS ，还是有些麻烦。&lt;/p&gt;
&lt;p&gt;最终，我选择了 mosdns 。它也存在缺点，比如 Homebrew 没有现成的安装包，需要手动部署；官方文档简洁，得结合 Github 仓库讨论区他人的配置文件来理解。但它的优点同样突出，可在不同地点自动选择默认的上游 DNS ，且支持正则表达式，匹配主机名、域名比 Dnsmasq 更精准。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/2025-02-01-20-04-13-DNS%20%E5%88%86%E6%B5%81%E6%8B%93%E6%89%91%E5%9B%BE.svg" alt="2025-02-01-20-04-13-DNS分流拓扑图"&gt;&lt;/p&gt;</description></item><item><title>探索 elmo.chat：AI 驱动的网页内容总结神器</title><link>http://0x3f.org/posts/elmo-chat-intro/</link><pubDate>Sat, 18 Jan 2025 20:57:56 +0800</pubDate><guid>http://0x3f.org/posts/elmo-chat-intro/</guid><description>&lt;h2 id="一邂逅-elmochat"&gt;一、邂逅 elmo.chat&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250118210106000-3a3998e062e6906cbbbc1ef8169e18a4.avif" alt="2025-01-18-21-01-06-ElmoChat-YourAIcompaniontocreatesummariesandinsights"&gt;&lt;/p&gt;
&lt;p&gt;在信息爆炸的时代，每天面对海量的网页、PDF 文档、YouTube 视频，是不是感觉时间完全不够用，根本看不过来？作为一个每天在互联网信息海洋里 “冲浪” 的博主，我也经常被这个问题困扰。直到有一天，我偶然发现了一款堪称 “神器” 的 Chrome 扩展 —— &lt;a href="https://www.elmo.chat/"&gt;elmo.chat&lt;/a&gt; ，它就像我的私人智能助手，能快速帮我提炼关键信息，大大提高了我的阅读和学习效率。今天就来给大家分享一下这款工具。&lt;/p&gt;
&lt;h2 id="二主要功能"&gt;二、主要功能&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250118210302000-28b2877f4ef71a7173e3794990633606.avif" alt="2025-01-18-21-03-02-mac_20250118202041"&gt;&lt;/p&gt;
&lt;h3 id="一网页内容速览"&gt;（一）网页内容速览&lt;/h3&gt;
&lt;p&gt;elmo.chat 最主要的功能，就是能把那些冗长又复杂的网页内容，快速转化成简短精炼的摘要。以前浏览资讯类网页，一大堆文字看得眼花缭乱，关键信息还不好找。现在有了 elmo.chat，点击一下扩展图标，几秒钟就能生成一份清晰的内容摘要，帮我迅速了解这篇文章到底在讲啥，大大节省了时间和精力。&lt;/p&gt;
&lt;h3 id="二覆盖多类型总结对象"&gt;（二）覆盖多类型总结对象&lt;/h3&gt;
&lt;p&gt;同时支持网页、YouTube 视频、PDF 文档、Google Docs 等多种格式的内容。&lt;/p&gt;
&lt;h3 id="三深度交互"&gt;（三）深度交互&lt;/h3&gt;
&lt;p&gt;这个功能让我觉得 elmo.chat 就像是一个智能小助手。它不仅能给出内容总结，还能针对总结的内容跟我进行深度交流。比如，我在阅读一篇关于人工智能发展趋势的文章后，对其中提到的某种新技术不太理解，就可以直接在 elmo.chat 的交互框里提问，它会根据文章内容给我做出详细的解释。这种交互体验，就像是身边有一位专业的顾问，随时为我答疑解惑，帮助我更深入地理解所阅读的内容。&lt;/p&gt;
&lt;h3 id="四多语言支持"&gt;（四）多语言支持&lt;/h3&gt;
&lt;p&gt;elmo.chat 还具备灵活的多语言支持，它会基于浏览器的语言设置，生成相应语言的总结内容。也可以自己指定语言。&lt;/p&gt;
&lt;h2 id="三免费使用"&gt;三、免费使用&lt;/h2&gt;
&lt;p&gt;不得不说，elmo.chat 的免费使用政策真的太贴心了！只要你安装了这款扩展，就能马上使用它的所有功能。不管是学生党想快速总结学习资料，还是打工人需要处理大量工作文档，都能毫无负担地使用 elmo.chat，不用担心会产生额外的费用，实实在在地降低了使用门槛，让每个人都能轻松享受到 AI 带来的便利。&lt;/p&gt;
&lt;h2 id="四使用过程中的问题"&gt;四、使用过程中的问题&lt;/h2&gt;
&lt;h3 id="一浏览器适配局限"&gt;（一）浏览器适配局限&lt;/h3&gt;
&lt;p&gt;美中不足的是，elmo.chat 在浏览器兼容性方面存在一定的局限性。官方明确表示，这款扩展仅支持 Chrome 浏览器，并且不支持基于 Chrome 的衍生浏览器。这对于习惯使用特定浏览器的用户来说，可能会有些不便。不过，经过我的实际测试，发现 Microsoft Edge 浏览器也能使用 elmo.chat，这算是一个小小的惊喜。但我目前的主力浏览器 Arc 却无法使用 elmo.chat，这让我在使用时不得不频繁切换浏览器，多少有些影响使用体验 。希望开发者后续能够扩大浏览器的支持范围，让更多用户能够方便地使用这款强大的工具。&lt;/p&gt;
&lt;h3 id="二侧边栏设计待优化"&gt;（二）侧边栏设计待优化&lt;/h3&gt;
&lt;p&gt;elmo.chat 的侧边栏设计初衷或许是为了实现对 PDF 的总结等功能，但在实际使用中却存在一些问题。它的侧边栏并非内嵌于网页之中，而是独立于网页之外。这就导致当我切换网页页签后，侧边栏会随之消失。要是我想再次查看总结内容，就必须回到原页签，重新执行总结操作，这一过程略显繁琐。若将侧边栏设置为始终显示，虽然能解决切换页签后消失的问题，但新的问题又出现了。在浏览那些不需要总结的网页时，侧边栏会一直占据屏幕空间，挤压网页的显示区域，让网页内容看起来很局促，影响正常的浏览体验。&lt;/p&gt;
&lt;h3 id="三主题设定存困惑"&gt;（三）主题设定存困惑&lt;/h3&gt;
&lt;p&gt;elmo.chat 提供了浅色和深色两种主题供用户选择，然而，这个主题设置却让人有些困惑。无论是选择浅色主题还是深色主题，侧边栏的背景颜色竟然都是黑色，两者的区别仅仅在于字体颜色，浅色主题下字体为白色，深色主题下字体为灰色。这种设定与我们通常对浅色和深色主题的认知不太一样，正常情况下，浅色主题的背景应该是明亮的色调。这一不太合理的主题设置，在一定程度上影响了使用的视觉感受和操作体验 。&lt;/p&gt;
&lt;h2 id="五结语"&gt;五、结语&lt;/h2&gt;
&lt;p&gt;总的来说，elmo.chat 作为一款功能强大的 Chrome 扩展，在信息总结和交互体验方面表现出色，为我们的学习、工作和研究带来了极大的便利。其免费使用的政策更是让广大用户能够轻松上手，享受 AI 技术带来的高效服务。但不可忽视的是，它在浏览器适配、侧边栏设计以及主题设置等方面还存在一些不足之处 。希望开发者能够重视这些问题，在后续的更新迭代中加以优化和改进。相信在未来，随着技术的不断进步和完善，elmo.chat 将为我们带来更加流畅、便捷的使用体验。如果你也被海量的信息所困扰，不妨尝试一下 elmo.chat，说不定它会成为你在信息海洋中航行的得力助手！&lt;/p&gt;</description></item><item><title>Whisper Keyboard: 非常好用的语音输入法</title><link>http://0x3f.org/posts/whisper-keyboard/</link><pubDate>Thu, 16 Jan 2025 23:29:46 +0800</pubDate><guid>http://0x3f.org/posts/whisper-keyboard/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250116233456000-5e4612d49d7845ec4655138667e2a1ae.avif" alt="2025-01-16-23-34-56-WhisperKeyboard"&gt;&lt;/p&gt;
&lt;p&gt;一直以来都在拿 ChatGPT 当语音输入法用，识别效果非常好，但毕竟还是不够方便。&lt;/p&gt;
&lt;p&gt;现在终于有好用的基于 Whisper 的语音输入法了，完成度很高，体验很好。目前阶段还是免费的。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://whisperkeyboard.app/"&gt;https://whisperkeyboard.app/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;罗老师的梦快要实现了。&lt;/p&gt;</description></item><item><title>《康熙的红票》讲了什么</title><link>http://0x3f.org/posts/a-brief-summary-of-kangxis-red-tickets/</link><pubDate>Tue, 14 Jan 2025 19:52:30 +0800</pubDate><guid>http://0x3f.org/posts/a-brief-summary-of-kangxis-red-tickets/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250114195420000-70057705f36660fc564e7d52cf66030c.avif" alt="2025-01-14-19-54-20-IMG_0224"&gt;&lt;/p&gt;
&lt;h1 id="红票的由来与意义"&gt;红票的由来与意义&lt;/h1&gt;
&lt;p&gt;1716 年康熙发出的红票，是寻找派往欧洲使团的公开信，体现了康熙朝的国际视野和开放态度。这也说明后来的禁教原因并不单纯是中西文化差异。&lt;/p&gt;
&lt;h1 id="教士与康熙朝的关系"&gt;教士与康熙朝的关系&lt;/h1&gt;
&lt;p&gt;那时候教士为了传教，用西方文化、艺术和科技来获取清朝上层好感。但康熙只看重西方技术的实用性，对底层科学和思想兴趣不大。康熙朝通过内务府管理教士，教士地位类似包衣，与皇帝更像主仆关系，所以他们能以私人关系接近权贵。正因如此，康熙以内务府接待教廷和沙皇使团，导致西方重要访华活动在清史中无记载。&lt;/p&gt;
&lt;h1 id="礼仪之争"&gt;礼仪之争&lt;/h1&gt;
&lt;p&gt;康熙朝后期，罗马教廷认为中国教徒祭祖祭孔违背教义，要求禁止，与清廷起了争议。这让清廷加强了对教士管理，但还不是禁教主因。&lt;/p&gt;
&lt;h1 id="禁教及其影响"&gt;禁教及其影响&lt;/h1&gt;
&lt;p&gt;雍正继位后禁教，一是他本人信佛且对西方文化技术不感兴趣，二是教士卷入政治斗争。雍正禁教，加上乾隆时耶稣会在欧洲受打压无法再派教士入华，中国就这样错过了 18 世纪西方科技革命的窗口期。&lt;/p&gt;
&lt;p&gt;总之，《康熙的红票》这本书让我们看到了康熙朝中西交流的复杂与多元，也让我们对那段历史有了更深刻的认识。&lt;/p&gt;</description></item><item><title>Kindle 11 代越狱过程中的一些问题</title><link>http://0x3f.org/posts/kindle-11th-gen-jailbreak-issues/</link><pubDate>Sun, 12 Jan 2025 21:31:26 +0800</pubDate><guid>http://0x3f.org/posts/kindle-11th-gen-jailbreak-issues/</guid><description>&lt;p&gt;前几天给 KO2 越狱十分顺滑，没想到昨天给抹茶做的时候竟然每一步都不顺利。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250112213719000-1e5a6249f9af0125255eaaa7f3dbf277.avif" alt="2025-01-12-21-37-19-IMG_3809"&gt;&lt;/p&gt;
&lt;p&gt;首先越狱一次没成功，安装 Update Hotfix 并重启后没有出现 Run Hotfix 项。然后重新执行越狱步骤后才成功。&lt;/p&gt;
&lt;p&gt;随后安装 KUAL 时提示“应用程序错误 所选应用程序无法启动”，不过安装后 KUAL 可用，就没有管它，算是有惊无险。&lt;/p&gt;
&lt;p&gt;最后，KOReader 安装后无法启动，没有任何提示，在他的目录中的 crash.log 里找到错误信息说是 reader.lua 文件找不到，但是对应的文件其实是存在的。KOReader 的 GitHub 仓库中有人反馈类似的问题，虽然跟我的情况不完全相同，但是试了一下，是行得通的，安装最新的 &lt;a href="https://fw.notmarek.com/khf/koreader/"&gt;nightly build&lt;/a&gt; 版本就行了。&lt;/p&gt;
&lt;p&gt;大概是因为新版的 Kindle 发布较晚，越狱程序和 KOReader 没有经过充分的测试，毕竟最初用的 KOReader 稳定版是几个月前发布的。&lt;/p&gt;</description></item><item><title>小米安防轻松入苹果“家门”，教你一招搞定！</title><link>http://0x3f.org/posts/control-xiaomi-alarm-system-using-homekit/</link><pubDate>Wed, 08 Jan 2025 18:00:33 +0800</pubDate><guid>http://0x3f.org/posts/control-xiaomi-alarm-system-using-homekit/</guid><description>&lt;h2 id="为什么这么做"&gt;为什么这么做？&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241225155254000-df8cb517762f17ae1523614c57beeb91.avif" alt="2024-12-25-15-52-54-ImageDec252024"&gt;&lt;/p&gt;
&lt;p&gt;小米官方 Home Assistant 集成的事件订阅机制可是一大亮点，它极大地解放了小米智能组件在 Apple 的 HomeKit 生态中的应用。以往三方集成采用轮询机制，这就导致小米多数的组件响应延迟很大，体验感极差。比如之前安防系统模式变化后几秒钟仪表盘上的组件才改变状态，实在是逼死强迫症。但现在不同了，有了事件订阅机制，组件响应十分及时，我们终于可以在家庭 App 中流畅地调用这些组件实现自动化操作了。&lt;/p&gt;
&lt;p&gt;不过，对于安防系统，小米官方 Home Assistant 集成目前只提供了一个下拉框组件。这在日常使用中可就有些不便了，当你想要快速查看安防状态或者切换模式时，还得费劲地去点开下拉框，既不美观，操作也麻烦。要是能在 Home Assistant 的仪表盘和 Apple 的家庭 App 中，显示专为安防系统设计的组件，那使用起来就顺手多了。所以，就需要把这个下拉框组件对应的 select 实体转换成 alarm_control_panel 实体，接下来就看看具体怎么做吧。&lt;/p&gt;
&lt;h2 id="实操"&gt;实操&lt;/h2&gt;
&lt;p&gt;首先，我们要创建一个 alarm_control_panel 实体，位置在：Settings → Devices &amp;amp; services → Helpers → Create helper → Template helper → Template an alarm control panel。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250108180403000-25935642a4bf6b303521653107296ab5.avif" alt="2025-01-08-18-04-03-alarm_01"&gt;&lt;/p&gt;
&lt;p&gt;在这里，我们需要用模板来进行配置，以下是关键的代码部分：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&lt;span class="l"&gt;% set state_map = {&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;#39;basic_arming&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;disarmed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;#39;home_arming&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;armed_home&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;#39;away_arming&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;armed_away&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;#39;sleep_arming&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;armed_night&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;}&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;%}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;{{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;state_map.get(states(&amp;#39;select.lumi_cn_463684587_mgl03_arming_mode_p_3_1&amp;#39;), &amp;#39;unknown&amp;#39;) }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这段代码的含义是，我们先定义了一个名为 &lt;code&gt;state_map&lt;/code&gt; 的字典，它将小米安防下拉框组件中的不同状态值（如 &lt;code&gt;basic_arming&lt;/code&gt; 等）对应翻译成苹果 HomeKit 能识别的 alarm_control_panel 实体状态值（如 &lt;code&gt;disarmed&lt;/code&gt; 等）。最后的 &lt;code&gt;{{ state_map.get(states('select.lumi_cn_463684587_mgl03_arming_mode_p_3_1'), 'unknown') }}&lt;/code&gt; 这部分，则是获取当前小米安防组件的状态，并通过前面的 &lt;code&gt;state_map&lt;/code&gt; 进行转换，如果获取状态失败，就返回 &lt;code&gt;unknown&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>法嘴转美嘴的转换头不像想像中好用</title><link>http://0x3f.org/posts/french-valve-to-american-valve-adapter-not-as-convenient-as-expected/</link><pubDate>Thu, 02 Jan 2025 17:16:12 +0800</pubDate><guid>http://0x3f.org/posts/french-valve-to-american-valve-adapter-not-as-convenient-as-expected/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250102171746000-7160eec9a1a0e99b70993ab41a12d7a2.avif" alt="2025-01-02-17-17-46-IMG_3644"&gt;&lt;/p&gt;
&lt;p&gt;我的气泵的美嘴比法嘴好用，所以想把轮胎的法嘴转换成美嘴。&lt;/p&gt;
&lt;p&gt;事先了解过，这种转换头即便打完气不摘下来，气密性也没有问题，实际用下来也确实如此。不过过段时间再打气的时候气泵的美嘴就卡不牢了，很容易弹出来，可能是里面法嘴气门的那个螺栓往回缩了。如果是很老式的那种夹式的气嘴夹头估计也能用，不过新式的就不行了。&lt;/p&gt;
&lt;p&gt;这样可能每次打气都需要把转换头拧出来再拧回去，而且转换头拧起来比气嘴帽困难多了，总体来说不但不方便，还更麻烦了。所以这个东西只能在没有法嘴气筒时临时应个急，不能一直装在上面。&lt;/p&gt;</description></item><item><title>通义千问的音视频速读功能很方便</title><link>http://0x3f.org/posts/qianwen-stt-is-convenient/</link><pubDate>Thu, 02 Jan 2025 11:32:38 +0800</pubDate><guid>http://0x3f.org/posts/qianwen-stt-is-convenient/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20250102113341000-1cee351ae61b01c15f64081f93ba7a33.avif" alt="2025-01-02-11-33-41-qianwen_stt_01"&gt;&lt;/p&gt;
&lt;p&gt;平时总有一些食之无肉弃之有味的音视频，我只想了解它的核心观点，而略过大部分的铺垫，这时候用语音转文字的工具把他转换成文本，再由 AI 总结就可以了。&lt;/p&gt;
&lt;p&gt;通义千问有音视频速读和链接速读的功能，用它速通了很多个视频、音频、播客、讲座，转换速读很快，会自动对文字转换稿做总结并生成脑图和要点，而且这个功能还是免费的。&lt;/p&gt;
&lt;p&gt;我一向不太喜欢通过音视频获取信息，因为效率太低了，现在 AI 帮我节省了大量时间，可以用来骑🚴车🚴‍♀️了🚴‍♂️&lt;/p&gt;</description></item><item><title>写了个方便添加 Miniflux 过滤规则的 Chrome 扩展</title><link>http://0x3f.org/posts/miniflux-enhancer-make-adding-miniflux-filter-rules-easier/</link><pubDate>Tue, 31 Dec 2024 23:02:02 +0800</pubDate><guid>http://0x3f.org/posts/miniflux-enhancer-make-adding-miniflux-filter-rules-easier/</guid><description>&lt;p&gt;Miniflux 是个可以自己部署的 RSS 阅读器，我用它省了每年几百块的 Inoreader 订阅费。&lt;/p&gt;
&lt;p&gt;为了提高阅读效率，经常需要给订阅源添加一些过滤规则，过滤掉不关心的内容。&lt;/p&gt;
&lt;p&gt;但是每次都修改订阅源的配置太麻烦了，所以我写了个 Chrome 浏览器的扩展，在每条阅读条目下面添加一个“更新规则”的按钮，这下方便多了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241231230453000-0aa31aa458f2001375067d203fb2fec1.avif" alt="2024-12-31-23-04-53-introduction-01-update-rules"&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/chrome-extension-miniflux-enhancer"&gt;https://github.com/xbot/chrome-extension-miniflux-enhancer&lt;/a&gt;&lt;/p&gt;</description></item><item><title>小米传感器“入驻”苹果家庭App，智能生活轻松拿捏</title><link>http://0x3f.org/posts/mapping-xiaomi-sensors-from-home-assistant-to-apple-home-app/</link><pubDate>Fri, 27 Dec 2024 22:20:44 +0800</pubDate><guid>http://0x3f.org/posts/mapping-xiaomi-sensors-from-home-assistant-to-apple-home-app/</guid><description>&lt;h2 id="一为什么要进行映射"&gt;一、为什么要进行映射？&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241225154931000-0a6a504d6406815842ce9e0cc194cca9.avif" alt="2024-12-25-15-49-31-mac_20241225154742"&gt;&lt;/p&gt;
&lt;p&gt;小米官方 Home Assistant 集成的事件订阅机制，极大的解放了小米智能组件在 Apple 的 HomeKit 生态中的应用！以往三方集成用的是轮询机制，这就导致小米多数组件响应特别慢，体验感超差。例如起夜时，我希望进入洗手间的同时夜灯就点亮，结果等了几秒它才有反应，是不是很让人抓狂？但现在不一样了，有了事件订阅机制，在家庭 App 里调用小米组件实现自动化变得轻松多了，大大提升了使用的流畅度。&lt;/p&gt;
&lt;p&gt;再说说小米的传感器，可能凡是电池供电的都是无状态的。就是只有被触发的时候，才会产生一个事件，而不是像有些传感器那样一直有个持续性的实时状态。所以在小米官方集成里，大多就只提供了一个 event 实体。&lt;/p&gt;
&lt;p&gt;反观家庭 App，里面的传感器是以 sensor 和 binary sensor 的形式存在的。它们都是有状态的实体，不同之处在于，sensor 的状态可以多种多样，能反映不同的数值或情况；而 binary sensor 呢，简单直接，只有两种状态，非此即彼。&lt;/p&gt;
&lt;p&gt;这么一看，问题就来了，要想在家庭 App 里用好小米传感器，就必须把 Home Assistant 里的那个 event 实体，转换成 sensor 或者 binary sensor，这样两边才能对上号，实现更智能的联动。&lt;/p&gt;
&lt;h2 id="二详细操作步骤"&gt;二、详细操作步骤&lt;/h2&gt;
&lt;h3 id="一创建存放触发时间的实体"&gt;（一）创建存放触发时间的实体&lt;/h3&gt;
&lt;p&gt;接下来，以小米夜灯的人体传感器为例，介绍实现这一转换的方法。&lt;/p&gt;
&lt;p&gt;首先，要创建一个 input_datetime 类型的实体，用来存放最近一次人体移动事件触发时间。在 Home Assistant 里，路径如下：Settings → Devices &amp;amp; services → Helpers → Create helper → Date and/or time。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241227225411000-7aaf9bf6e03a3da7bf8be1dd5d3cb4a3.avif" alt="2024-12-27-22-54-11-sensor_02"&gt;&lt;/p&gt;
&lt;h3 id="二创建更新实体的自动化"&gt;（二）创建更新实体的自动化&lt;/h3&gt;
&lt;p&gt;紧接着，创建一个 Automation，用于在传感器的 event 触发时保存当前时间到前面那个实体。同样在 Home Assistant 里，找到 Settings → Automations &amp;amp; scenes → Create automation 这个路径。&lt;/p&gt;</description></item><item><title>小米官方的 Home Assistant 集成一周体验</title><link>http://0x3f.org/posts/one-week-experience-of-xiaomi-official-home-assistant-integration/</link><pubDate>Wed, 25 Dec 2024 14:58:27 +0800</pubDate><guid>http://0x3f.org/posts/one-week-experience-of-xiaomi-official-home-assistant-integration/</guid><description>&lt;h2 id="消息订阅机制--最大亮点"&gt;消息订阅机制 —— 最大亮点&lt;/h2&gt;
&lt;p&gt;小米官方 Home Assistant 集成最大的优势，就是其基于消息订阅机制的通信方式。这相较于第三方集成常用的轮询方式，有着质的飞跃。在以往的第三方集成中，设备状态的获取往往依赖于轮询，每隔一段时间才去检查设备状态是否有变化，这就导致了信息的延迟，用户操作后不能及时得到设备的反馈，体验大打折扣。&lt;/p&gt;
&lt;p&gt;而小米官方集成的消息订阅机制则像是给设备安装了一个实时传声筒。当设备属性发生改变或者有事件产生时，设备会迅速向小米云或小米中枢网关发送上行消息，米家集成就能在第一时间接收到这些消息并更新设备状态，无需频繁地刷新查询。这就使得小米的智能家居配件在 Home Assistant 和 HomeKit 生态中的响应变得极其及时，真正实现了设备状态的实时掌控。比如灯的开关、窗帘的开合、空调的温度调节等操作，都能瞬间得到执行和反馈，让用户感受到智能家居的便捷与高效，极大地提升了用户的智能家居体验。&lt;/p&gt;
&lt;h2 id="oauth2-登录方式--可能每周都要重新登录"&gt;OAuth2 登录方式 —— 可能每周都要重新登录&lt;/h2&gt;
&lt;p&gt;小米官方 Home Assistant 集成采用的 OAuth2 登录方式，其实有着诸多安全性方面的优势。它允许客户端不接触用户密码，服务器端能够更集中地保护用户信息，所有认证和授权信息都汇聚在服务器端，而非分散于各个客户端，大大减少了用户凭据泄露的风险。而且 OAuth2 还是一个应用广泛的认证标准，很多公司和组织都采用了它，这也让小米的智能家居配件在集成应用时更容易与其他平台或服务进行交互、整合。&lt;/p&gt;
&lt;p&gt;然而，在实际使用一周的体验中，也发现了不太方便的地方，那就是登录有效期的问题。使用一周之后，系统就会提示登录过期，需要重新登录。这在日常使用中，尤其是频繁操作智能家居设备时，还是挺影响体验的。每隔一段时间都要重新登录，操作步骤变得繁琐，打断了原本便捷的智能家居操控流程。&lt;/p&gt;
&lt;p&gt;据说这个 bug 会在未来的版本中解决。&lt;/p&gt;
&lt;h2 id="额外配置"&gt;额外配置&lt;/h2&gt;
&lt;h3 id="安防控制面板显示"&gt;安防控制面板显示&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241225155254000-df8cb517762f17ae1523614c57beeb91.avif" alt="2024-12-25-15-52-54-ImageDec252024"&gt;&lt;/p&gt;
&lt;p&gt;对于我在用的小米智能多模网关，小米官方 Home Assistant 集成并没有提供 HA 的安防控制面板实体，而是提供了一个基本的 select 实体。如果要在 HA 的仪表板和家庭 App 中显示安防控制面板，就需要把安防系统的 select 实体转换成 alarm_control_panel 实体。&lt;/p&gt;
&lt;h3 id="传感器实体转换"&gt;传感器实体转换&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241225154931000-0a6a504d6406815842ce9e0cc194cca9.avif" alt="2024-12-25-15-49-31-mac_20241225154742"&gt;&lt;/p&gt;
&lt;p&gt;对于移动检测传感器和烟雾传感器这样的配件，小米官方 Home Assistant 集成没有提供对应的 binary_sensor 实体，而是 event 实体，这当然很符合小米配件的行为模式，但如果需要把它们输出到 Apple 的家庭 App ，就需要将其转换成 binary_sensor 实体。这是因为家庭 App 无法处理 HA 中的 event 实体，而转换成binary_sensor 实体才能被识别为对应的传感器，也更便于与其他智能设备进行联动。&lt;/p&gt;</description></item><item><title>我为什么用 linkding 自建书签管理服务</title><link>http://0x3f.org/posts/why-do-i-use-linkding-as-my-bookmark-manager/</link><pubDate>Fri, 13 Dec 2024 00:55:08 +0800</pubDate><guid>http://0x3f.org/posts/why-do-i-use-linkding-as-my-bookmark-manager/</guid><description>&lt;h1 id="一为什么需要独立书签管理服务"&gt;一、为什么需要独立书签管理服务&lt;/h1&gt;
&lt;h2 id="1-降低迁移浏览器成本"&gt;1. 降低迁移浏览器成本&lt;/h2&gt;
&lt;p&gt;在我们日常使用浏览器的过程中，经常会遇到需要更换主力浏览器的情况。而每次迁移浏览器时，重新导入书签是一件非常繁琐的事情。有了独立的书签管理服务，就可以大大降低这种迁移成本。我们无需再为了导入书签而耗费大量时间和精力，轻松实现浏览器的切换。&lt;/p&gt;
&lt;h2 id="2-降低同步数据成本"&gt;2. 降低同步数据成本&lt;/h2&gt;
&lt;p&gt;在使用多个浏览器或者在不同设备（如在家和公司电脑）之间切换时，书签的同步问题常常让人头疼。如果没有独立的书签管理服务，我们可能需要依赖浏览器自带或者某些插件提供的同步功能，但这往往会带来数据错乱和丢失的风险。而有了独立的书签管理服务，我们就可以避免这些问题，确保书签数据的安全和稳定。&lt;/p&gt;
&lt;h2 id="3-方便管理"&gt;3. 方便管理&lt;/h2&gt;
&lt;p&gt;Raycast 插件是一个非常强大的工具，结合相关插件，可以让我们方便地搜索书签，并且能够对书签进行修改或删除操作。相比之下，以前使用的 Raycast 浏览器书签插件虽然搜索功能好用，但是缺乏管理功能。有了独立的书签管理服务，我们就可以充分发挥 Raycast 的优势，更加高效地管理我们的书签。&lt;/p&gt;
&lt;h1 id="二为什么自建书签管理服务"&gt;二、为什么自建书签管理服务&lt;/h1&gt;
&lt;p&gt;数据掌握在自己手中，配合 3 - 2 - 1 备份策略，既省钱又放心。&lt;/p&gt;
&lt;p&gt;在当今数字化的时代，我们的生活越来越依赖于各种电子设备和在线服务。然而，这也带来了一个问题，那就是我们的数据安全和隐私问题。如果我们仅仅依赖于浏览器自带的书签同步功能，那么我们的数据就可能会面临被泄露、丢失或者被篡改的风险。&lt;/p&gt;
&lt;p&gt;而自建书签管理服务，就可以很好地解决这个问题。通过自建书签管理服务，我们可以将自己的数据掌握在自己的手中，不用担心数据被第三方机构窃取或者滥用。同时，我们还可以配合 3 - 2 - 1 备份策略，确保我们的数据安全可靠。&lt;/p&gt;
&lt;p&gt;3 - 2 - 1 备份策略是一种非常有效的数据备份方法，它的基本原理是：至少保留 3 份数据备份，存储在 2 种不同的介质上，并确保 1 份备份异地存储，以提高数据安全性和恢复能力。这样，即使我们的硬盘损坏、电脑被盗或者遭遇自然灾害，我们的数据也不会丢失。&lt;/p&gt;
&lt;p&gt;自建书签管理服务可以让我们更加方便地实施 3 - 2 - 1 备份策略。我们可以将书签数据备份到本地硬盘、外部硬盘或者云存储服务上，确保我们的数据安全可靠。同时，我们还可以定期对备份数据进行检查和更新，确保备份数据的完整性和可用性。&lt;/p&gt;
&lt;p&gt;总之，自建书签管理服务可以让我们的数据更加安全可靠，同时也可以让我们更加方便地管理和使用自己的数据。如果你还在为数据安全和隐私问题而担忧，那么不妨考虑自建书签管理服务，让你的数据掌握在自己的手中。&lt;/p&gt;
&lt;h1 id="三linkding-的特点"&gt;三、linkding 的特点&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241213234505000-94c9d576eb4d482f828beff8eace8740.avif" alt="2024-12-13-23-45-05-linkding"&gt;&lt;/p&gt;
&lt;h2 id="简洁高效"&gt;简洁高效&lt;/h2&gt;
&lt;p&gt;linkding 的用户界面设计简洁直观，没有复杂的布局和过多的干扰元素。无论是网页界面还是移动端应用，都以清晰的布局和简洁的设计呈现，让用户能够快速聚焦于书签内容本身。优化后的可读性使得用户可以轻松浏览和管理自己的书签，无需在繁琐的界面中费力寻找所需信息。&lt;/p&gt;
&lt;p&gt;linkding 强调快速和无干扰的操作体验。用户可以高效地进行各种书签管理操作，如添加、编辑、删除等。其操作流程简单明了，无需复杂的步骤即可完成对书签的管理。无论是在忙碌的工作中还是日常的浏览中，linkding 都能让用户节省时间，提高效率。&lt;/p&gt;
&lt;h2 id="功能丰富"&gt;功能丰富&lt;/h2&gt;
&lt;p&gt;标签分类：linkding 支持基于标签的书签组织方式，用户可以根据自己的需求和喜好为书签添加各种标签。这种多标签的方式使得书签的分类更加灵活多样，用户可以通过点击相应的标签快速找到所需的书签。例如，用户可以为一个关于编程的网页添加 “编程”、“Python”、“开发工具” 等多个标签，当需要查找 Python 相关的书签时，只需搜索或点击 “Python” 标签即可。&lt;/p&gt;
&lt;p&gt;批量编辑：linkding 提供批量编辑功能，用户可以一次性对多个书签进行相同的操作。比如，当用户需要为一批书签添加相同的标签或修改注释时，可以使用批量编辑功能，大大提高了书签管理的效率。无需逐个编辑书签，节省了大量的时间和精力。&lt;/p&gt;</description></item><item><title>给 Raycast 的 linkding 扩展加了点功能</title><link>http://0x3f.org/posts/added-some-features-to-the-linkding-extension-of-raycast/</link><pubDate>Mon, 09 Dec 2024 22:11:03 +0800</pubDate><guid>http://0x3f.org/posts/added-some-features-to-the-linkding-extension-of-raycast/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241209222845000-512187e891a5c5f85a38f40b73b1e58d.avif" alt="2024-12-09-22-28-45-Image1080x1439"&gt;&lt;/p&gt;
&lt;p&gt;上周六风很大，被迫放弃去大运河骑车，窝在家里改 Raycast 的 linkding 扩展。&lt;/p&gt;
&lt;p&gt;Raycast 是一个 macOS 上的应用启动器和效率工具，类似 Spotlight 和 Alfred ，可以快速访问各类应用、文件等。linkding 是一个可以自己部署的书签管理工具，可以替代浏览器的书签管理功能，同时提供更强大、更灵活的特性。Raycast 的 linkding 扩展可以对存储在 linkding 中的书签做快速检索和管理的操作。&lt;/p&gt;
&lt;p&gt;这个扩展原本的界面和功能比较简陋，我给它加了以下内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可选择是否在列表中显示网站的图标。&lt;/li&gt;
&lt;li&gt;可选择是否在列表中显示副标题。&lt;/li&gt;
&lt;li&gt;可选择副标题区域显示网址的描述或者备注。&lt;/li&gt;
&lt;li&gt;增加编辑书签的功能。&lt;/li&gt;
&lt;li&gt;创建和编辑书签时可以给书签打 tag 。&lt;/li&gt;
&lt;li&gt;删除书签和 linkding 账户时弹出确认对话框，防止误删。&lt;/li&gt;
&lt;li&gt;增加在浏览器中打开 linkding 书签查看和编辑页面的功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241209223605000-e578367ecc02299350c5848e71cc46c5.avif" alt="2024-12-09-22-36-05-Image1500x948(1)"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241209223654000-7e977cf5742fcd5adde84afaf1209536.avif" alt="2024-12-09-22-36-54-Image1500x948"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241209223724000-28af3ef3e932537e7b8beee1b3b92dcf.avif" alt="2024-12-09-22-37-24-Image1662x1080"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241209223755000-90d3b2869838a5f80b860da4ba411e22.avif" alt="2024-12-09-22-37-55-Image1500x948(2)"&gt;&lt;/p&gt;
&lt;p&gt;在原作者合并 PR 之前，可以下载这个 &lt;a href="https://github.com/xbot/raycast-linkding"&gt;repo&lt;/a&gt; 的源码，并执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>两只猫的肠胃炎历险记</title><link>http://0x3f.org/posts/how-i-cured-my-cats-gastroenteritis/</link><pubDate>Wed, 30 Oct 2024 22:43:19 +0800</pubDate><guid>http://0x3f.org/posts/how-i-cured-my-cats-gastroenteritis/</guid><description>&lt;p&gt;上月中旬，发现两只猫分别出现软便、频繁呕吐的现象，以为是寄生虫的问题，用大宠爱和海乐妙做了内外驱。&lt;/p&gt;
&lt;p&gt;观察了几天，喂了乳酸菌素片之后软便现象好转，但没有根除，而呕吐的现象时轻时重，后来发展成呕吐物中带血丝或者粉水的程度。感觉问题严重了，准备去医院检查一下。&lt;/p&gt;
&lt;p&gt;但是两只猫都是从小收养，除了刚开始的一两年打疫苗，之后几乎没出过门，现在大了反而没有小时候胆大，一出门就应激，喊得全小区的灯都亮了。不得已放弃。&lt;/p&gt;
&lt;p&gt;根据它俩最近的情况，判断应该是换季+换粮导致的肠胃炎，买了阿莫西林克拉维酸钾颗粒和奥美拉唑肠溶胶囊，按前者 12.5-25mg/kg 、后者 1mg/kg 的剂量结合每只猫的体重喂服，一天两次。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241030224722000-59dd06ca92bdf508ba7472500bea7d8a.avif" alt="2024-10-30-22-47-22-IMG_3253"&gt;&lt;/p&gt;
&lt;p&gt;喂药是个艰苦卓绝的活儿，阿莫西林还算简单，混到罐头里就行，胶囊因为是肠溶的，需要直接吞服，可费老劲了，不过虽然直接喂死活不吃，但是有次喂完老大，身心俱疲地去洗了个手，回来发现它把老二的胶囊偷吃了！贱不贱，你就说贱不贱！&lt;/p&gt;
&lt;p&gt;就这样喂了三天，期间喂用温水泡发的干粮，少食多餐，之前的症状没了，就停了药。但是一吃干粮就容易吐，吃湿粮和罐头不吐，判断是肠胃还比较虚弱，所以又继续喂了一两周的湿粮。&lt;/p&gt;
&lt;p&gt;现在一个月过去了，已经完全康复了。&lt;/p&gt;</description></item><item><title>做完这些事，佰客城市版国布就可以毕业了（上）</title><link>http://0x3f.org/posts/the-final-build-of-my-domestic-brompton-like-folding-bike-part-1/</link><pubDate>Fri, 18 Oct 2024 00:08:40 +0800</pubDate><guid>http://0x3f.org/posts/the-final-build-of-my-domestic-brompton-like-folding-bike-part-1/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241018001921000-35b0bd08e130235fc9639cd36bdf1bac.avif" alt="2024-10-18-00-19-21-3ed0731e2f0f20835a0580d09d305986"&gt;&lt;/p&gt;
&lt;h1 id="车把"&gt;车把&lt;/h1&gt;
&lt;p&gt;M 把的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;蓝图 A7 这个指拨太长，微调旋钮离 M 把很近，所以变速线改为从头管后侧走线，这导致在头管上安装水壶架变得很困难。&lt;/li&gt;
&lt;li&gt;抛光银的反光左右不一致，导致看起来车把左右不对称。虽然实际骑起来感受不到明显的差异，但是强迫症还是比较难受。&lt;/li&gt;
&lt;li&gt;时速 22 公里以上不好发力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;改成直把可以解决以上问题。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241018002001000-2aa0eac1112902f3c6a247b03c2e011c.avif" alt="2024-10-18-00-20-01-IMG_3189"&gt;&lt;/p&gt;
&lt;h1 id="座垫"&gt;座垫&lt;/h1&gt;
&lt;p&gt;原装座垫非常不舒服，我穿骑行裤骑了不到 30 公里就屁股疼，需要换一个适合自己的座垫。&lt;/p&gt;
&lt;p&gt;佰客新版的座垫应该有所改进，但我没体验过。&lt;/p&gt;
&lt;h1 id="脚踏"&gt;脚踏&lt;/h1&gt;
&lt;p&gt;原装铝合金折叠脚踏容易异响，而且鞋底沾点水就非常滑。有拎车需求的话换快拆脚踏，没有就用普通脚踏，英布原装的单边折叠脚踏也是个不错的选项。&lt;/p&gt;
&lt;p&gt;佰客城市版新版的脚踏应该防滑性上好一些，其他方面不好评价，没有体验过。&lt;/p&gt;
&lt;h1 id="货架"&gt;货架&lt;/h1&gt;
&lt;p&gt;原装货架除了好看全是缺点。CNC 铝合金零件拼装的，强度很差，折叠后不能为车身提供足够的支撑力，表现为在地铁、公交上能看到折叠后的车身相对于货架出现明显的晃动，以及推行的时候出现相对严重的偏向问题。这个问题同时削弱了折叠后的稳定性，为了解决这个问题，原装货架上内置了易行轮伸缩杆的结构。伸缩杆的问题有两个，一是增加了一步操作，非常麻烦，二是强度差，在地铁站这种遍布盲道的地面拉开伸缩杆推行容易坏，不拉开容易倒，只能在折叠后静置停放时使用，有点鸡肋。&lt;/p&gt;
&lt;p&gt;曾经换装过青春版的货架，焊接一体的结构决定了在支撑力和一体性方面远超城市版，但它的问题一是比较粗大，外观和城市版不太协调，二是品控一般，有一个易行轮不着地。&lt;/p&gt;
&lt;p&gt;最后我换装了这个一百块出头的货架，重量更轻，外观比同为焊接、喷砂银的青春版货架更好看，四轮着地，推行和静置时比之前两个稳了很多。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241018002035000-91f541ffb108b137bbc9d816877bac46.avif" alt="2024-10-18-00-20-35-IMG_3190"&gt;&lt;/p&gt;
&lt;h1 id="挡泥板"&gt;挡泥板&lt;/h1&gt;
&lt;p&gt;一副挡泥板最大的耻辱就是挡不了泥，而它做到了。佰客的挡泥板一是没有挡泥皮，二是后挡太短，会有少量的泥水甩到身上。据说可以安装如图所示的挡泥皮，但是因为佰客的挡泥板只能搭配同厂货架使用，而我想换掉货架，所以选择直接换装英布的后挡泥板。此外，我用一块人造革给前挡剪了一片挡泥皮。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241018002227000-bbdfa4eb74e89c7d6f869d8a23ec1f89.avif" alt="2024-10-18-00-22-27-IMG_3193"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241018002054000-f356b9d6f206dcc7b8a9b83360de918e.avif" alt="2024-10-18-00-20-54-IMG_3191"&gt;&lt;/p&gt;
&lt;p&gt;佰客新版后挡泥板加装了挡泥皮。&lt;/p&gt;
&lt;h1 id="总结"&gt;总结&lt;/h1&gt;
&lt;p&gt;小布这个车型对我而言最大的价值是方便实用，所以我不喜欢牺牲这个核心价值的任何“改进”。佰客城市版车架比较接近英布，这意味着我对某些不喜欢的地方做改装的时候麻烦会少一些。没有做加大开档、拉长大梁、跟风上碟刹这种不可逆的负优化，是我选它的一个重要原因。&lt;/p&gt;
&lt;p&gt;另一个原因是外观。佰客的漆面质量不错，主色漆面和配色银色都是亮面，符合我当时的审美。不过佰客的颜色饱和度都偏低，而且几乎全部是冷色，不太讨喜，毕竟大车要稳、小车要骚，谁不想拥有一辆小红车呢？&lt;/p&gt;</description></item><item><title>记第一次补胎</title><link>http://0x3f.org/posts/my-first-tire-repair/</link><pubDate>Mon, 14 Oct 2024 23:11:33 +0800</pubDate><guid>http://0x3f.org/posts/my-first-tire-repair/</guid><description>&lt;p&gt;要说还是正新的胎不好，其它几辆车都是世文，最少的骑了一千多公里，最多的三千公里，一次都没扎过，这辆 Dash Altena 到手一个月，才三百多公里，就扎了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241014231339000-bfeed6a9e658328604b4688350cefaf5.avif" alt="2024-10-14-23-13-39-IMG_3147"&gt;&lt;/p&gt;
&lt;p&gt;以前只是理论上会补胎，看过教学视频，正好想实践一下，这不机会就来了么。&lt;/p&gt;
&lt;p&gt;买了补胎套装，补的还不错，骑了一圈长安街，降温后人少多了，均速第一次上了 26 。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241014231410000-3d3394a5b1315dd1337ad25fff6f5d20.avif" alt="2024-10-14-23-14-10-IMG_3159"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241014231433000-7aeb04ecd2e74e5dbe631e381f3e8640.avif" alt="2024-10-14-23-14-33-IMG_3158"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241014231459000-5c5915b9797273f4d90bacace812f0dd.avif" alt="2024-10-14-23-14-59-IMG_3160"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20241014231516000-3a151d77c14e592c3d92b31e716f5450.avif" alt="2024-10-14-23-15-16-IMG_3163"&gt;&lt;/p&gt;
&lt;p&gt;实践出真知，再扎就换胎！&lt;/p&gt;</description></item><item><title>用 n8n 优化 Homelab 通知流程：从邮件到 Telegram</title><link>http://0x3f.org/posts/optimize-homelab-notifications-with-n8n-from-email-to-telegram/</link><pubDate>Fri, 06 Sep 2024 16:27:57 +0800</pubDate><guid>http://0x3f.org/posts/optimize-homelab-notifications-with-n8n-from-email-to-telegram/</guid><description>&lt;p&gt;最近，我对 Homelab 的通知系统进行了一次升级，将繁琐的邮件通知转变为简洁的 Telegram 消息。这个过程不仅提高了效率，还大大改善了我的使用体验。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;我的 Homelab 基础设施主要由 Proxmox Virtual Environment (PVE) 和 Proxmox Backup Server (PBS) 构成。这些系统每天都会发送各种通知，包括系统更新、虚拟机和容器备份、备份数据仓库垃圾回收等任务的执行结果。&lt;/p&gt;
&lt;p&gt;长期以来，我一直通过邮件接收这些通知。然而，邮件作为一种信息接收方式，显得既重量级又低效。每天删除这些通知邮件成了一件烦人的琐事，我急需一种更轻量、更即时高效的通知方式。&lt;/p&gt;
&lt;h2 id="为什么选择-telegram"&gt;为什么选择 Telegram？&lt;/h2&gt;
&lt;p&gt;我已经在使用 Telegram 接收 Unraid 的通知消息，体验一直很不错。考虑到这点，我决定将基础平台的通知也集中到 Telegram 上来。&lt;/p&gt;
&lt;h2 id="初步尝试gotify-和-gotify2telegram"&gt;初步尝试：Gotify 和 gotify2telegram&lt;/h2&gt;
&lt;p&gt;PVE 和 PBS 除了支持邮件通知，还支持 Gotify 这个消息收集服务。理论上，我可以使用 &lt;a href="https://github.com/anhbh310/gotify2telegram"&gt;gotify2telegram&lt;/a&gt; 插件将 Gotify 的消息转发到 Telegram。&lt;/p&gt;
&lt;p&gt;但是，这个方案存在两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不支持通过 Gotify 的 Application 过滤消息，导致所有发送到 Gotify 的消息都会被无差别转发。&lt;/li&gt;
&lt;li&gt;不支持对消息内容进行处理，降低了通知的可读性。比如，PVE 在备份客户机后会发送冗长的备份过程信息，这些信息在 Telegram 中会被截断成多条消息展示，非常不便于阅读。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="最终方案n8n--gotify-webhook"&gt;最终方案：n8n + gotify-webhook&lt;/h2&gt;
&lt;p&gt;为了解决上述问题，我找到了 &lt;a href="https://github.com/wuxs/gotify-webhook"&gt;gotify-webhook&lt;/a&gt; 插件。我的想法是通过这个插件将消息转发给 n8n 处理，然后再发送到 Telegram。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240906163319000-aa034016c15fc28cd1ee86c78541649e.avif" alt="2024-09-06-16-33-19-mac_20240905114752"&gt;&lt;/p&gt;
&lt;p&gt;在提交了一个 PR 并被合并后，我终于实现了这个流程。现在，我的 Homelab 通知体验有了质的飞跃：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;消息经过 n8n 处理后更加简洁明了。例如，对于备份任务，如果成功了只会发送一条简短的成功通知，只有在失败时才会显示详细信息。&lt;/li&gt;
&lt;li&gt;通过 n8n 的规则，我可以轻松过滤和分类不同类型的通知。&lt;/li&gt;
&lt;li&gt;Telegram 的即时性让我能够更快地响应任何潜在的问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;通过这次升级，我不仅简化了 Homelab 的日常维护工作，还提高了对系统状态的感知能力。如果你也在为繁琐的 Homelab 通知所困扰，不妨试试这个方案。&lt;/p&gt;</description></item><item><title>在 Mac 上玩儿红警 2</title><link>http://0x3f.org/posts/play-ra2-on-mac/</link><pubDate>Thu, 22 Aug 2024 17:23:26 +0800</pubDate><guid>http://0x3f.org/posts/play-ra2-on-mac/</guid><description>&lt;p&gt;最近在 YouTube 上看红警的视频，了解了一下主播用的对战平台，不仅仅是个当年浩方的翻版，而是进一步整合了红警游戏，等于是个带联网功能的红警，用着很方便。&lt;/p&gt;
&lt;p&gt;用 CrossOver 安装了红警 2 和鸿图对战平台，除了后者配置游戏的几个选项无法点击外，游戏运行效果堪称完美。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240822172746000-9e88ae21fb7ae735b476f3eb01cab705.avif" alt="2024-08-22-17-27-46-IMG_2777"&gt;&lt;/p&gt;
&lt;p&gt;对战平台不能选择玩家、阵营，虽然游戏运行没问题，可玩性大打折扣。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240822173453000-ca2545e1ccb50092521a2eb7e6980e4a.avif" alt="2024-08-22-17-34-53-1531724315569_.pic"&gt;&lt;/p&gt;
&lt;p&gt;安装过程很简单，安装完程序在 wine 的设置里把 ddraw 加上就行。&lt;/p&gt;</description></item><item><title>突然成了 Up 主</title><link>http://0x3f.org/posts/suddenly-became-a-youtuber/</link><pubDate>Thu, 15 Aug 2024 15:46:29 +0800</pubDate><guid>http://0x3f.org/posts/suddenly-became-a-youtuber/</guid><description>&lt;p&gt;早在一年前还在用 Inoreader 的时候就发现 Calibre 抓取某些订阅源之后图片不显示了，后来迁移到 Miniflux ，由于 Calibre 抓取的是它缓存的网页内容，所以这个问题暂时被规避了。现在改用 Readwise Reader 挑拣稍后读的内容，图片的问题又出现了，甚至增加了文章内容为空的情况。&lt;/p&gt;
&lt;p&gt;抽时间调试了一下，发现图片不显示是因为 Calibre 在抓取时没有发送 Referer 的 HTTP 报文头，内容为空是因为文章格式较为特殊（比如链接相对正文的比重较大）、导致 Calibre 当成非正文内容过滤掉了。&lt;/p&gt;
&lt;p&gt;然后了解了一下 Calibre Recipe 。官方文档比较简单，需要看源码辅助理解，有些问题还需要通过调试找到切入点。终于解决了所有问题，又可以用 Calibre Content Server 的网页端快乐地阅读了。&lt;/p&gt;
&lt;p&gt;突然觉得这种比较小的点很适合用短视频的形式表达，所以买了一个月剪映会员，用截图和录屏做了一个 30 秒的视频，旁白用 AI 语音，效果还不错。平时看过一些类似形式做的长视频，TTS 波澜不惊的颜色听多了挺难受，不过短视频就不存在这个问题，观众还没有疲劳就结束了。&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/uzQpO_G_vPg?si=8FBqc40NyFSyvlXZ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;</description></item><item><title>给佰客城市版国布更换青春版货架</title><link>http://0x3f.org/posts/replacing-the-rack-of-bikes-folding-bike-with-the-se-version/</link><pubDate>Mon, 29 Jul 2024 00:00:00 +0800</pubDate><guid>http://0x3f.org/posts/replacing-the-rack-of-bikes-folding-bike-with-the-se-version/</guid><description>&lt;p&gt;佰客城市版的货架是由多个 CNC 铝合金零件组装起来的，而且包含了易行轮的伸缩杆结构。系统越复杂，稳定性越差。此外，可能是为了颜值和重量，零件较为细小，进一步降低了强度。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240728232111000-2f052724e5ef335028502c5b2bba52cf.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这个货架作为停车支架用是没有问题的，但如果经常推行或者搭乘公共交通工具，就不好用了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;易行轮伸缩杆很细，推行时，如果不拉开，车子容易倒，如果拉开，经过非纯平地面（比如地铁站里的盲道）的时候容易颠坏。&lt;/li&gt;
&lt;li&gt;货架强度不足以承托车身重量，在车身重心靠右的情况下，推行极易向左偏，地铁晃动的时候，车身会在货架上小幅度晃来晃去，晃得多了，螺丝就松了，零件之间的形变也会变大，导致产生异响。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;佰客新出了银色的青春版货架，我买了一个，换掉了才用了不到一个月的城市版货架。青春版货架是焊接的一个整体，喷砂银，重量比城市版轻 50g 左右，外观不如城市版的好看，但是强度好得多，现在推行体验好多了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240728232233000-7748d610406e784da9bc78e5bb4abff5.avif" alt=""&gt;&lt;/p&gt;
&lt;p&gt;不过仍然存在 4 个易行轮三轮着地一轮悬空的问题，可能是货架的公差较大，也可能是车架的精度问题。&lt;/p&gt;
&lt;p&gt;城市版货架是个不太成功的设计，为了美观牺牲了实用性，在承重的关键位置用了复杂而脆弱的系统。佰客如果重视口碑的话，应该重新设计，并给买过车的客户一个实惠的升级价格。&lt;/p&gt;</description></item><item><title>佰客城市版国布的走线问题</title><link>http://0x3f.org/posts/wiring-issue-of-the-bikes-folding-bike/</link><pubDate>Sun, 28 Jul 2024 19:42:29 +0800</pubDate><guid>http://0x3f.org/posts/wiring-issue-of-the-bikes-folding-bike/</guid><description>&lt;p&gt;佰客城市版国布的变速线是在头管内侧走线的，这会严重影响像 Fidlock 这样的水壶架的安装。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240612165248000-cdc1f4c5a970873be112cb55a04bace6.avif" alt="2024-06-12-16-52-48-DSC00243"&gt;&lt;/p&gt;
&lt;p&gt;这个问题应该跟指拨有关。佰客用的蓝图 A7 ，这是一款山地车指拨，长度较长，尤其在 M 把上微调旋钮离车把很近，走线空间非常有限。&lt;/p&gt;
&lt;p&gt;这个问题在 S 把上就不存在，事实上，看照片，用 S 把的佰客无界版就是在外侧走线的。&lt;/p&gt;
&lt;p&gt;我之前吐槽过这个指拨用在小布车架上不合理，为了缓解拨柄顶着大拇指的问题，需要把指拨向内侧平移一段距离，但这样微调旋钮就更接近 M 把了，更难通过头管外侧走线。&lt;/p&gt;
&lt;p&gt;而且小布的走线角度相比大行、风行的车的更大，这就导致微调旋钮处的线管受力很大。我的新车到手两个月，受力处的线管外的包胶就已经开裂了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240728194501000-32c89ae04d7f6ed16bf5bc1d6de25ce9.avif" alt="2024-07-28-19-45-01-F28F4E05-12CA-464A-BF2E-689E9F6B3FF4"&gt;&lt;/p&gt;
&lt;p&gt;所以国布要想做好，这个指拨是一定要重新设计的。&lt;/p&gt;
&lt;p&gt;看照片，R 布的指拨似乎用的也是蓝图 A7 ，但是走线是在外侧，所以买车前可能可以要求佰客改一下走线方式或者用 S 把，以免日后遇到这么尴尬的问题。&lt;/p&gt;</description></item><item><title>心率带的平替：用华为手环 9 在自行车码表上显示心率</title><link>http://0x3f.org/posts/huawei-band-9-as-a-heart-rate-monitor/</link><pubDate>Thu, 25 Jul 2024 00:42:45 +0800</pubDate><guid>http://0x3f.org/posts/huawei-band-9-as-a-heart-rate-monitor/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240725004802000-eb86c1bf07929b11123a4105230f96dc.avif" alt="2024-07-25-00-48-02-IMG_2526"&gt;&lt;/p&gt;
&lt;p&gt;用华为手环 9 的心率广播功能在码表上显示心率，测试了一周，体验不错。&lt;/p&gt;
&lt;p&gt;在选品前，考虑了 Apple Watch 、心率带（胸带）、心率带（臂带）和手环。&lt;/p&gt;
&lt;p&gt;Apple Watch 本身没有心率广播功能，需要通过 iPhone 上的第三方 App 实现，但是会和码表 App 产生冲突，必须解绑后者才能广播心率，用起来太麻烦。&lt;/p&gt;
&lt;p&gt;心率带（胸带）使用心电原理测心率，准确度高，实时性好，续航长，价格低，但是使用麻烦，舒适性差。&lt;/p&gt;
&lt;p&gt;心率带（臂带）使用和 Apple Watch 相同的光电原理测测心率，准确度、实时性、续航的表现都弱于胸带，价格更贵，但是方便性和舒适性更好。&lt;/p&gt;
&lt;p&gt;手环也是光电原理，在测心率方面的优缺点可以和臂带等量齐观，但功能更多、使用场景更多、价格差不多甚至更低。&lt;/p&gt;
&lt;p&gt;考虑到我的应用场景：普通人；市区道路；折叠车；主要目的是锻炼、骑游和通勤，方便性和舒适性是很重要的选品标准。&lt;/p&gt;
&lt;p&gt;综合考虑，手环应该是个合适的选择。&lt;/p&gt;
&lt;p&gt;实际用下来，准确度可以和 Apple Watch 相提并论，实时性方面查到的可信数据是比胸带延时 4 到 5 秒左右，这就足够非专业运动员和无特殊医疗需求的普通人使用了。续航方面，心率广播状态下，每小时耗电大约是 2% ，完全不会有电量焦虑。&lt;/p&gt;</description></item><item><title>这款 MKS 塑料脚踏是我国布折叠车的最优解</title><link>http://0x3f.org/posts/mks-ux-d-pedal/</link><pubDate>Tue, 23 Jul 2024 15:27:41 +0800</pubDate><guid>http://0x3f.org/posts/mks-ux-d-pedal/</guid><description>&lt;p&gt;经过半个月的漫长等待，海淘的 MKS UX-D 非快拆脚踏终于到了，和之前买的快拆版一起，组了一副单边快拆脚踏。一副维格 V984T 在两辆车上来回倒腾的日子结束了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240723153140000-219e8ada50ff533310c3153cb9f986a9.avif" alt="2024-07-23-15-31-40-E222BA44-2408-4E83-B554-930D24760B70"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240723153305000-21352b4a65bb7a79c8ec39d4b9e301bb.avif" alt="2024-07-23-15-33-05-E40C8889-B3BF-43A3-828B-A67F70295E9B"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240723153439000-ca74f5d4fc089a575ec5659d92c670d4.avif" alt="2024-07-23-15-34-39-5AA9B9C9-5239-4327-B6C6-C518A58D4620"&gt;&lt;/p&gt;
&lt;p&gt;我的佰客城市版的原装折叠脚踏，在骑了不到两个月、里程不到一千公里的时候，异响到了让我难以忍受的程度。虽然我仍然认为折叠脚踏是最适合折叠车的，但市面上为数不多的那几款挑来挑去都不太满意，只能退而求其次，从快拆脚踏里找。&lt;/p&gt;
&lt;p&gt;这个过程仍然不轻松，因为大部分快拆脚踏都是我不喜欢的金属脚踏。在我看来，金属脚踏除了好看之外都是缺点，因为自身的特性，金属脚踏只能通过增大压强的方式防滑，比如钉踏，比如在竖直的金属片上刻齿，压强越大，和脚的接触面积越小，也就越伤鞋、越容易刮伤腿，不适合我这种喜欢穿着随意、主要在市区道路骑折叠车的普通人。尤其是在另一辆 KA349 上用了维格 V984T 之后，我现在挑脚踏都优先考虑塑料的了，塑料脚踏除了颜值不如金属之外都是优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;防滑且不伤鞋和腿&lt;/li&gt;
&lt;li&gt;和脚的接触面积大，踩着舒服&lt;/li&gt;
&lt;li&gt;轻&lt;/li&gt;
&lt;li&gt;便宜&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我想要塑料的快拆脚踏，但这似乎是个不可能完成的任务，直到找到 MKS UX-D ，大概市面上只有这么一款塑料的快拆脚踏。试骑了 30 公里，整体满意，符合预期，甚至颜值也不输金属，只是踏面稍小，踩上没有 V984T 那种人车合一的包覆感。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240723153504000-ca6be17d62c7de518d17046b017f908e.avif" alt="2024-07-23-15-35-04-72320DB0-90D6-4C4C-B280-52E03A223569"&gt;&lt;/p&gt;</description></item><item><title>打通稍后读工作流：Readwise Reader 的 RSSHub 路由发布</title><link>http://0x3f.org/posts/rsshub-route-for-readwise-reader-is-published/</link><pubDate>Thu, 11 Jul 2024 17:33:26 +0800</pubDate><guid>http://0x3f.org/posts/rsshub-route-for-readwise-reader-is-published/</guid><description>&lt;p&gt;本文聊聊在从 Inoreader 迁移到 Miniflux 后，我是怎样重建我的阅读工作流的。&lt;/p&gt;
&lt;h2 id="原来的阅读工作流"&gt;原来的阅读工作流&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240711174910000-269332b48a7ac704a29ed2284ce95357.avif" alt="The previous reading workflow"&gt;&lt;/p&gt;
&lt;p&gt;在用过的 RSS 阅读器里，Inoreader 最符合我的阅读习惯。它有以下优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文章去重和过滤&lt;/strong&gt;：由于订阅的资讯较多，这个功能能帮我节省很多时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接近 Vim 风格的快捷键&lt;/strong&gt;：Vim 用户表示极度舒适。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多种布局&lt;/strong&gt;：为不同的订阅源指定最合适的布局能极大提高阅读效率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持把标签输出为订阅源&lt;/strong&gt;：方便通过 Calibre 订阅和抓取。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我在 Inoreader 里只做快速浏览，对需要阅读的文章打星标，随后集中对星标文章打标签。然后在 Calibre 里抓取指定标签的文章并生成电子书，既可以在 Calibre Content Server 的网页端阅读，也可以发送到 Kindle 离线阅读。&lt;/p&gt;
&lt;h2 id="电脑上的阅读体验"&gt;电脑上的阅读体验&lt;/h2&gt;
&lt;p&gt;在电脑上，我一直钟爱使用 Calibre Content Server 的网页端进行阅读。它具备以下特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自适应多栏布局&lt;/strong&gt;：针对高分屏的优化，使得阅读体验更加舒适。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;卡片式翻页&lt;/strong&gt;：与传统的滚动式翻页相比，卡片式翻页在提高阅读效率的同时，也更加护眼。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自定义排版样式&lt;/strong&gt;：可以根据自己的喜好调整阅读界面，打造个性化的阅读环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240711180602000-e5452f135375f5c8395551fefe8f9b2b.avif" alt="2024-07-11-18-06-02-IMG_2332"&gt;&lt;/p&gt;
&lt;h2 id="从-inoreader-到-miniflux-的转变"&gt;从 Inoreader 到 Miniflux 的转变&lt;/h2&gt;
&lt;p&gt;后来，Inoreader 的价格涨了很多，我尝试自建 Miniflux ，效果意外地好，但它有一个明显的局限性：只支持打星标，不支持打标签。这意味着我无法像使用 Inoreader 那样，通过标签对文章进行筛选和分类。&lt;/p&gt;
&lt;h2 id="readwise-reader-的优势"&gt;Readwise Reader 的优势&lt;/h2&gt;
&lt;p&gt;不过 Miniflux 支持集成 Readwise Reader 。它不仅支持标签功能，还提供了列表接口。这让我意识到，如果能够将 Readwise Reader 的文档输出为订阅源，那么我的稍后读工作流将更加完善。&lt;/p&gt;
&lt;h2 id="rsshub-路由发布"&gt;RSSHub 路由发布&lt;/h2&gt;
&lt;p&gt;为了实现这一目标，我为 RSSHub 添加了一个路由，它可以将 Readwise Reader 的文档转换成订阅源。这样一来，我就可以在 Calibre Content Server 中愉快地阅读那些稍后阅读的文章了。&lt;/p&gt;</description></item><item><title>体验精致与舒适：佰客城市版国产小布折叠车详评</title><link>http://0x3f.org/posts/hands-on-the-city-version-of-bikes-folding-bike/</link><pubDate>Wed, 12 Jun 2024 15:31:07 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-the-city-version-of-bikes-folding-bike/</guid><description>&lt;p&gt;分享一下佰客国布城市版 2024 新版的开箱和骑行感受。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240612165248000-cdc1f4c5a970873be112cb55a04bace6.avif" alt="2024-06-12-16-52-48-DSC00243"&gt;&lt;/p&gt;
&lt;h1 id="tldr"&gt;TL;DR&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;整车比较精致，个别细节有待加强。&lt;/li&gt;
&lt;li&gt;非常好骑，轮组很润。&lt;/li&gt;
&lt;li&gt;比英布 C Line 和一般国布轻一点，不多。&lt;/li&gt;
&lt;li&gt;除了座垫要到手换，整车无须大改，属于一辆到手就能骑的车。&lt;/li&gt;
&lt;li&gt;解决了一些英布的问题，但还有优化的空间。&lt;/li&gt;
&lt;li&gt;配色少，且以冷色为主。&lt;/li&gt;
&lt;li&gt;磨合期会遇到一些小问题，线上售后会耐心解答和指导解决（可能没有专职的售后，有时候不能及时响应），需要一些简单的动手能力。没有体验过线下售后。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="开箱感受"&gt;开箱感受&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;包装很紧凑&lt;/strong&gt;：只有座垫和脚踏需要自己安装，据说以后整车都是装好的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;做工整体较为精致&lt;/strong&gt;：用了很多 CNC 的银色部件，质感很好，抛光银的燕把和座管比磨砂银更有高级感，线管是透明表面+银色螺旋（可能是金属）内衬，有质感，银色的夹器和刹把好看，但表面近看有点粗糙，据说城市版是铜焊，漆水厚实，不像风行的漆那么脆皮。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;肉球把套挺舒服&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轮组很润&lt;/strong&gt;：花鼓声音不大，很润，实际骑行感受非常好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自带延长杆的易行轮货架&lt;/strong&gt;：CNC 货架很精致，重量更轻，拉开易行轮的延长杆可以解决折叠后重心不稳的问题，个人以为不如青春版那种 Q 版货架实用，拉开延长杆毕竟多出一步操作，比较麻烦，而且延长杆比较脆弱，不适合在拉开的状态下推行，可说是为了颜值和轻量化牺牲了实用性了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预置了驻车盘&lt;/strong&gt;：解决座管不完全放下时拎车散架的问题，方便推车过程中临时拎车。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;尾灯很好用&lt;/strong&gt;：座垫自带充电尾灯，挺好用，安装接口不通用，换座垫后用不了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;塑料猪鼻座&lt;/strong&gt;：比铝合金的实用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;细节处理&lt;/strong&gt;：脚踏安装孔预涂了润滑脂，刹车块是可替换刹皮的刹车靴。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="磨合期遇到的一些问题"&gt;磨合期遇到的一些问题&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;座管抛光层剥落&lt;/strong&gt;：开箱就是抛光层剥落的座管，卖家寄了新的座管。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;座管下滑&lt;/strong&gt;：调紧座管夹可以解决，但锁和解锁座管夹会更费力，需要多次尝试、找到一个平衡点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;座管夹头复杂且不支持碳弓&lt;/strong&gt;：座管复刻英布，夹头复杂、安装麻烦，且安装碳弓座垫需要换夹组（不便宜），暂时放弃使用碳弓座垫，改用钛弓。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;座垫有翘翘板现象&lt;/strong&gt;：卖家说需要 25nm 的扭力，但还是会有轻微的问题，不过并不影响乘坐舒适度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;座垫不舒服&lt;/strong&gt;：仿棒槌哥 AEOLUS comp 座垫，比较硬且中间的空隙很长很宽，穿上骑行裤骑 30km 也难受，换了 TAOZIK 的钛弓座垫，好多了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;指拨不舒服&lt;/strong&gt;：指拨用的蓝图 A7，柄较长，顶着大拇指，握把和变速都很难受，把指拨往远离把套的方向移动一段距离后，问题得到缓解，蓝图 A7 不是为小布设计的，直接拿来用体验不好，和“国布天花板”、“精益求精”的宣传给我拉高的预期有差距。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;变速跳档&lt;/strong&gt;：第三次骑的过程中出现变速跳档的现象，微调拧紧变速线之后，问题解决。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C 扣限位影响展开流畅度&lt;/strong&gt;：C 扣限位是为了解决英布 C 扣扳手可能拧脱和 C 扣可能转动的问题，大梁上的 C 扣拧松后会向前倾斜导致短边会卡住折叠关节边缘，使车头部分的关节无法和大梁部分闭合，而当左手从车头离开去调整 C 扣时，在非纯平地面容易出现折叠关节重新展开导致很狼狈的问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;挡泥板效果不完美&lt;/strong&gt;：后挡泥板较短，会有少量泥水被甩出来，可能安装挡泥皮后能解决，但平价配件很难找，应该预置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;脚踏的踏感一般&lt;/strong&gt;：景晔的这款铝合金折叠脚踏做工不错，也好看，但是重量较大，有点滑、不抓脚。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轮胎亏气&lt;/strong&gt;：骑了三次才发现轮胎的气压只有 40 多 PSI，补气后好骑多了，理解可能是为了防止运输的过程中爆胎，但给一个明确的提示会好得多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推行向左偏&lt;/strong&gt;：因为重心靠右，通过改变推行姿势缓解：不要握着座垫鼻，而是扶着座垫右后方。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;颜色少且缺乏暖色&lt;/strong&gt;：的确有冷色更耐看的说法，但个人更喜欢车架是暖色，显得有生气。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重量比宣传的重&lt;/strong&gt;：宣传的 9.5kg 是不带挡泥板和货架的，客服说加上后是 10+ kg，到手是 11.4kg，卖家解释是淘宝页面及客服掌握的信息更新不及时，新版做了一些优化和加强后重量有所上升，可以理解。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="更新"&gt;更新&lt;/h1&gt;
&lt;h2 id="2024-07-29"&gt;2024-07-29&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/posts/replacing-the-rack-of-bikes-folding-bike-with-the-se-version"&gt;更换青春版货架&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2024-07-28"&gt;2024-07-28&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/posts/wiring-issue-of-the-bikes-folding-bike"&gt;走线的问题&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2024-07-23"&gt;2024-07-23&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/posts/mks-ux-d-pedal"&gt;换了 MKS 塑料脚踏&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2024-06-29"&gt;2024-06-29&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;换掉了原装脚踏&lt;/strong&gt;：踩踏过程中出现了异响，而且鞋底沾水之后非常滑，不光影响骑感，也不安全。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换了改良版货架&lt;/strong&gt;：原装货架有设计缺陷，导致发生了断裂的问题，卖家寄了改良版，断裂位置不再使用螺丝固定，理论上降低了问题重现的概率。不过这种用 CNC 零件和钢螺丝组装的货架在重量和强度上天生不足，属于是为了颜值牺牲这两点了，使用时还得多加小心。市面上有些用铝合金管材焊接的一体货架，重量轻很多，精度未知，理论上强度应该会更好一些，就是不如 CNC 的好看。Ruhm 那种一体铸造的货架也挺精致，如果能在强度过关的前提下再轻一些（ 400 多克，比佰客城市版货架重 100 多克），就更好了。不管怎样，对于小布的货架，实用性是第一位的，其次是颜值，最后是重量，佰客城市版的货架多少有点本末倒置了。
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240629222557000-54d146e5afb52b986c7467c24c778afa.avif" alt="2024-06-29-22-25-57-IMG_2284"&gt;
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240629222629000-d5f656f3ce6195046c73f8d9480bbbe0.avif" alt="2024-06-29-22-26-29-IMG_2305"&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>15￥ 包邮的尼龙脚踏，实现了我对休闲骑行脚踏的所有想象</title><link>http://0x3f.org/posts/wellgo-v984t-pedal/</link><pubDate>Wed, 22 May 2024 18:57:03 +0800</pubDate><guid>http://0x3f.org/posts/wellgo-v984t-pedal/</guid><description>&lt;h2 id="休闲骑行脚踏的选择"&gt;休闲骑行脚踏的选择&lt;/h2&gt;
&lt;p&gt;休闲骑行的特点是单段持续时间较长、需要保持和队友的节奏，对车的好骑程度要求较高，对折叠便利性和折叠体积要求低。&lt;/p&gt;
&lt;p&gt;在选择休闲骑行的脚踏时，我考虑了以下几种类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;锁踏&lt;/strong&gt;：由于市区路况复杂，休闲骑行不追求速度，因此锁踏并不适合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;钉踏&lt;/strong&gt;：市面上产品众多，价格和外观选择丰富。但钉踏容易伤鞋，也容易把腿划破。之前买了用圆头防滑钉、号称不伤鞋的辉哥 J6 脚踏，骑了一个月也磨坏了运动鞋底的防滑纹。
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240523105503000-ce00dc4fb9ab8a487cde423996856c89.avif" alt="2024-05-23-10-55-03-IMG_1909"&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平踏&lt;/strong&gt;：最适合市区骑游的场景，我的期望是：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;大踏面&lt;/strong&gt;：提供舒适的踩踏体验。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;抓脚但不伤鞋&lt;/strong&gt;：在保证稳定性的同时，不伤鞋。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重量轻&lt;/strong&gt;：对于折叠、携带的要求不高，可以牺牲快拆或折叠功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我了解或使用过的脚踏包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MKS&lt;/strong&gt;：重量较重，价格较高。
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240523111407000-59dc71c7c14ff5e078464b44d4c642b7.avif" alt="2024-05-23-11-14-07-IMG_1920"&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;维格 M111 类似脚踏&lt;/strong&gt;：外观相似，采用 DU 轴或 DU + 单培林，在平踏中较为常见，视觉效果简洁，价格不贵，但踏面较小。包括：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;M111&lt;/strong&gt;：外观、做工、重量表现最佳，价格最贵。
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240523110154000-9d35806a669f0dffb8b896463a3bc154.avif" alt="2024-05-23-11-01-54-IMG_1916"&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;M248&lt;/strong&gt;：做工一般，踏面和轴用螺丝结合。
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240523110452000-59c95f9c6786c4f9788dfe13206797e9.avif" alt="2024-05-23-11-04-52-IMG_1917"&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;M921&lt;/strong&gt;：做工好，一体成形，漆面光滑。（下图右侧）
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240523110629000-a746750be91e494d2301cd94818b7d65.avif" alt="右侧 M921 左侧 Jifo 原装脚踏"&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;大行 Jifo 原装快拆脚踏&lt;/strong&gt;：快拆设计方便，但安装复杂，且难以购买。（上图左侧）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LP 的快拆脚踏&lt;/strong&gt;：一体成形，但漆面差。
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240523111204000-a8cd7b434e6408f4e7d100cbb3c18c82.avif" alt="2024-05-23-11-12-04-IMG_1919"&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终，我选择了维格的尼龙脚踏 V984T 。&lt;/p&gt;
&lt;p&gt;维格提供了多种尼龙脚踏，我选择的是体积较小、重量较轻、与车外观搭配较为协调的 V984T 。它满足了我对配件和脚踏的所有选择标准，而且价格仅为 15￥ 包邮。这款脚踏的踩踏体验极为舒适，脚掌与踏面的贴合度非常好，有人体工学的感觉，超过了以往用过的所有脚踏。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240523111513000-ae842b6fc709f0ce210c0c29ad06bcf4.avif" alt="2024-05-23-11-15-13-IMG_1911"&gt;&lt;/p&gt;
&lt;h2 id="关于脚踏润度的题外话"&gt;关于脚踏润度的题外话&lt;/h2&gt;
&lt;p&gt;理论上，润度更高的脚踏可以提高踩踏效率，但对于我们普通人在市区道路上的骑行场景来说，追求高润度并没有太大意义。DU 轴的脚踏已经完全够用，既满足了日常需求，又保持了合理的价格。&lt;/p&gt;</description></item><item><title>Jifo 前刹的改造之路：好事多磨</title><link>http://0x3f.org/posts/the-end-of-road-to-modifying-jifos-front-brake/</link><pubDate>Mon, 29 Apr 2024 21:33:01 +0800</pubDate><guid>http://0x3f.org/posts/the-end-of-road-to-modifying-jifos-front-brake/</guid><description>&lt;p&gt;&lt;a href="http://0x3f.org/posts/the-road-to-modifying-jifos-front-brake/"&gt;上次&lt;/a&gt;尝试过彰星夹器后，我用回了原装的单轴夹器。但是前刹手感差、刹车力弱、刹臂移动距离不对称的问题一直困扰着我。直到最近找到了价格合适的大行夹器。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240429214024000-eceec2102f4cf44f1bc3712f14dd619a.avif" alt="2024-04-29-21-40-24-IMG_1656"&gt;&lt;/p&gt;
&lt;p&gt;这个夹器主体看起来和 eezz 的原装夹器一样，只是螺帽螺杆是公路车那种隐藏式的，而且是后刹。我没有 eezz ，不了解原装后刹是什么样的。&lt;/p&gt;
&lt;p&gt;用上次改装彰星夹器的物料改装了一下：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240429214622000-89b381f3c5982c919be10b8ab8c38dd1.avif" alt="2024-04-29-21-46-22-IMG_1657"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240429214625000-7eb23b00ba480ecb2e915132f0092217.avif" alt="2024-04-29-21-46-25-IMG_1659"&gt;&lt;/p&gt;
&lt;p&gt;安装测试，结果很完美，刹车力、刹车手感和颜值都有了很大提升。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240429214751000-a16ef566dfb367d0d77721ff03a42ff8.avif" alt="2024-04-29-21-47-51-IMG_1661"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240429214754000-3006937d8c16d30a1c40f5b66993b1fa.avif" alt="2024-04-29-21-47-54-IMG_1662"&gt;&lt;/p&gt;
&lt;p&gt;粗略了解了一下脱漆、抛光、抗氧化的方法，觉得太麻烦，没有处理成银色，好在黑色夹器并不明显，在 Jifo 这车上也不违和，就这样吧。&lt;/p&gt;</description></item><item><title>修复绝版老车 Jifo 的张链器：一次艰难的维修之旅</title><link>http://0x3f.org/posts/fixing-the-chain-tensioner-of-dahon-jifo/</link><pubDate>Wed, 24 Apr 2024 15:38:37 +0800</pubDate><guid>http://0x3f.org/posts/fixing-the-chain-tensioner-of-dahon-jifo/</guid><description>&lt;p&gt;拥有一辆绝版老车 Jifo ，就像拥有一个珍贵的老友。然而，当它出现问题时，维修之路往往充满挑战。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240115201620000-05158d1dfd5ac42f0a751ba6dc2dd4ee.avif" alt="2024-01-15-20-16-20-e3e356bd402bd5fcb4157225c29f5966"&gt;&lt;/p&gt;
&lt;p&gt;在前不久的一次骑行中，我的 Jifo 飞轮突然发生跳齿。回家后，我检查发现问题出在张链器的弹簧上——它断了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154917000-15c9737facde3619d906974ab94989e7.avif" alt="2024-04-24-15-49-17-IMG_1541"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154923000-58fdde7acc7f19e0559fc3cc6b1ab72a.avif" alt="2024-04-24-15-49-23-IMG_1539"&gt;&lt;/p&gt;
&lt;p&gt;由于 Jifo 使用的是非标件，市场上很难找到合适的替换件，而且价格昂贵。因此，我决定尝试寻找第三方的平替产品。&lt;/p&gt;
&lt;h1 id="便宜的替代品"&gt;便宜的替代品&lt;/h1&gt;
&lt;p&gt;我首先尝试了两种便宜的替代品。由于导链轮和基座之间的距离较大且无法调节，它们并不适合Jifo。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154142000-adc25ce6fc7ca950fb1350ae8173a319.avif" alt="2024-04-24-15-41-42-IMG_1677"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154146000-c021f9cf660757c78458023cc034d3c3.avif" alt="2024-04-24-15-41-46-IMG_1676"&gt;&lt;/p&gt;
&lt;h1 id="碳客和禧玛诺"&gt;碳客和禧玛诺&lt;/h1&gt;
&lt;p&gt;尽管我没有实际测试过这两款产品，但从图片上看，它们似乎也存在同样的问题。碳客的款式虽然距离可调，但最小距离可能仍然超出 Jifo 的规格。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154258000-8be889d3ca3fbeb1cd06ac4d2e6ed918.avif" alt="2024-04-24-15-42-58-IMG_1679"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154303000-808540cc1dfb48a74147ef4934be9322.avif" alt="2024-04-24-15-43-03-IMG_1678"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154306000-45ff4e763ee4c491486f6dfd0111543d.avif" alt="2024-04-24-15-43-06-IMG_1680"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154310000-0f26785488332137224c5aa6f96bfe44.avif" alt="2024-04-24-15-43-10-IMG_1681"&gt;&lt;/p&gt;
&lt;h1 id="muqzi"&gt;MUQZI&lt;/h1&gt;
&lt;p&gt;我随后尝试了 MUQZI 的张链器，它的调节范围较大，可以使用。然而，实际使用中，链条会蹭到导链轮两侧的挡板，这也不是理想的解决方案。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154425000-39bdbbd6221dee05f4fe19d09f446c39.avif" alt="2024-04-24-15-44-25-IMG_1674"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154435000-b56b815c75b8e42e471ed98781c458aa.avif" alt="2024-04-24-15-44-35-IMG_1675"&gt;&lt;/p&gt;
&lt;h1 id="回归原装"&gt;回归原装&lt;/h1&gt;
&lt;p&gt;最终，我决定回归使用原装的张链器。尽管价格昂贵，且未来寻找替换件同样困难，但它体积小、重量轻，安装方便，且不需要截断链条。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424154837000-06c48ce4ba1658e749f2a45da32959ea.avif" alt="2024-04-24-15-48-37-IMG_1533"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240424161954000-1404521da5fac62d3f4c37a057a8335a.avif" alt="2024-04-24-16-19-54-IMG_1683"&gt;&lt;/p&gt;
&lt;h1 id="结语"&gt;结语&lt;/h1&gt;
&lt;p&gt;在安装过程中，我发现这辆车之前进行过不太成功的改装。尾钩安装张链器的孔中有四分之三的螺纹已经滑丝。幸运的是，目前还能固定住。我计划稍后使用螺丝胶进行加固。如果螺纹完全滑丝，我将不得不考虑使用丝锥和丝套来挽救，这是一体尾钩设计的一个潜在弊端。&lt;/p&gt;</description></item><item><title>Unraid 启动 U 盘损坏：症状、解决方案与备份恢复</title><link>http://0x3f.org/posts/how-to-recover-from-a-crash-of-the-unraid-flash-drive/</link><pubDate>Fri, 23 Feb 2024 16:23:33 +0800</pubDate><guid>http://0x3f.org/posts/how-to-recover-from-a-crash-of-the-unraid-flash-drive/</guid><description>&lt;p&gt;在 Unraid 操作系统的日常使用中，启动 U 盘的损坏可能会导致一系列问题，从而影响到整个系统的稳定性和数据的安全性。本文将探讨启动 U 盘损坏时的表现、解决办法，以及如何通过备份恢复系统。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240223163319000-994f57360279dd899ddf0c399d4987af.avif" alt="2024-02-23-16-33-19-Aid1Uo"&gt;&lt;/p&gt;
&lt;h2 id="启动-u-盘损坏的表现"&gt;启动 U 盘损坏的表现&lt;/h2&gt;
&lt;p&gt;当你的 Unraid 系统遇到以下情况时，很可能是启动 U 盘出现了问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只读模式&lt;/strong&gt;：在尝试启动 Unraid 时，系统可能会提示文件系统为只读，导致无法正常启动。这种情况下，服务器可能会卡住，无法进入操作界面。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;磁盘工具无法修复&lt;/strong&gt;：如果尝试将 U 盘插入 Mac 电脑，并使用磁盘工具的 First Aid 功能，但无法修复问题，这进一步证实了 U 盘的损坏。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="恢复备份的步骤"&gt;恢复备份的步骤&lt;/h2&gt;
&lt;p&gt;面对启动 U 盘的损坏，恢复备份是解决这一问题的有效方法。以下是详细的恢复步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;下载闪存备份&lt;/strong&gt;：首先，你需要从 Unraid Connect 下载你的闪存备份。这通常可以通过 Unraid 的 WebGUI 界面完成。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用 Unraid USB Creator&lt;/strong&gt;：接下来，使用 Unraid USB Creator 工具将备份恢复到一个新的 U 盘。这个工具可以在 Windows 或 macOS 上运行，并且可以从 Unraid 官网下载。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;启动并重新授权&lt;/strong&gt;：在新的 U 盘上恢复备份后，你需要启动 Unraid 系统。启动后，进入 Main 页面，获取你的 Key 文件，并按照提示重新授权。这将确保你的 Unraid 系统能够识别新的启动 U 盘。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="参考资源"&gt;参考资源&lt;/h2&gt;
&lt;p&gt;在处理启动 U 盘损坏的问题时，以下官方文档提供了宝贵的指导：&lt;/p&gt;</description></item><item><title>我的 iGPSPORT iGS630S 体验：告别手机与手表，拥抱专业骑行伴侣</title><link>http://0x3f.org/posts/hands-on-igpsport-igs630s/</link><pubDate>Thu, 22 Feb 2024 20:51:59 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-igpsport-igs630s/</guid><description>&lt;p&gt;多年前，我曾使用过非智能的码表，那时的骑行记录简单而纯粹。随着时间的推移，我更换了折叠车，骑行更多是为了休闲和享受。在这个阶段，手机和智能手表已经足够满足我记录骑行数据的需求，而且我并不喜欢在车上挂太多东西，保持简洁是我的风格。&lt;/p&gt;
&lt;p&gt;然而，随着 Apple Watch S4 的续航能力逐渐下降，加之 iPhone 在极端气温下续航表现不佳，我开始考虑寻找一款能够替代这些设备的智能码表。在尝试了 iGPSPORT BSC200 后，我发现其路线导航功能很鸡肋，在路况复杂的地方非常难用，这促使我转向了 iGPSPORT iGS630S 。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240222211303000-3395efe0724d3a5d447f22898dd7643d.avif" alt="2024-02-22-21-13-03-IMG_1092"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240222212002000-c3a4f3c6de9c467881801e5b87b53a52.avif" alt="2024-02-22-21-20-02-IMG_1208"&gt;&lt;/p&gt;
&lt;p&gt;iGS630S 给我的第一印象是其搜星速度非常快，这对于户外骑行来说是一个巨大的优势。在实际使用中，尽管它的续航时间并没有达到宣传的 45 小时，但至少 25 小时的续航能力已经足够我完成大部分骑行活动。定位和测速的准确性也让我印象深刻，尤其是在通过立交桥而失去卫星信号时，它没有出现像手机和手表那样夸张的失准问题。&lt;/p&gt;
&lt;p&gt;在使用路书导航时，iGS630S 的表现尤为出色。它的地图导航功能直观易用，让我在复杂的路况中也能轻松找到正确的路线。此外，它还配备了光感功能，能够在隧道等光线较暗的环境中自动调整屏幕亮度，这一点在实际骑行中非常实用。&lt;/p&gt;
&lt;p&gt;iGS630S 的手机 App 设计同样令人满意。界面美观、简洁，操作流畅，完全符合我对智能设备的审美要求。这使得数据同步和路线规划变得异常便捷，极大地提升了我的骑行体验。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240222212427000-e9f9dfdc8fd0f8dd80346d635869f646.avif" alt="2024-02-22-21-24-27-3D01C7B9-6110-4EBF-9F06-906D18D46E4E_1_102_o"&gt;&lt;/p&gt;
&lt;p&gt;当然，任何产品都有其不足之处。在使用 iGS630S 进行位置点导航时，我发现其路线规划能力相较于手机地图有所不足。此外，当偏离预定路线时，它的自动规划速度也不如手机地图响应迅速。在外观设计上，iGS630S 也不如 BSC 系列那样吸引人。&lt;/p&gt;
&lt;p&gt;总的来说，iGPSPORT iGS630S 是一款功能强大、续航可靠的智能码表。尽管在某些方面还有待改进，但它已经足够满足我对智能骑行的所有期待。对于追求高效、便捷骑行体验的骑手来说，iGS630S 无疑是一个值得考虑的选择。&lt;/p&gt;</description></item><item><title>从 Inoreader 到 Miniflux：寻找理想的 RSS 阅读器之旅</title><link>http://0x3f.org/posts/replacing-inoreader-with-miniflux/</link><pubDate>Tue, 13 Feb 2024 21:51:59 +0800</pubDate><guid>http://0x3f.org/posts/replacing-inoreader-with-miniflux/</guid><description>&lt;p&gt;在信息爆炸的时代，我们每天都在被各种新闻、文章和更新淹没。作为一个热衷于高效获取信息的读者，我一直在寻找一个理想的 RSS 阅读器，它能够让我快速筛选出感兴趣的内容，同时提供舒适的阅读体验。经过多年的探索，Inoreader 成为了我的首选，它几乎满足了我对 RSS 阅读器的所有期望。然而，最近 Inoreader 的价格调整让我不得不重新审视我的选择。&lt;/p&gt;
&lt;h1 id="我理想中的-rss-阅读器"&gt;我理想中的 RSS 阅读器&lt;/h1&gt;
&lt;p&gt;我理想中的 RSS 阅读器应该具备以下几个特点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;关键词过滤&lt;/strong&gt;：这让我能够避免浪费时间在不感兴趣的内容上，专注于那些真正有价值的信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多种视图支持&lt;/strong&gt;：至少包括列表和卡片视图，这样我可以为不同的订阅源选择最合适的视图。例如，对于变形金刚的优惠信息，卡片视图能让我一眼看到感兴趣的型号。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;稍后读功能&lt;/strong&gt;：RSS 阅读器对我来说主要是快速浏览的工具，对于那些需要深入阅读的内容，我希望能够标记为稍后阅读。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快捷键支持&lt;/strong&gt;：快捷键能够极大提高我的阅读效率，让我在浏览时更加得心应手。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="inoreader-的变迁"&gt;Inoreader 的变迁&lt;/h1&gt;
&lt;p&gt;Inoreader 在过去几年里几乎完全符合我的需求，即使在前两年涨价后，它仍然允许老用户以原价续费，这让我感到非常满意。然而，最近我收到了一封邮件，通知我年费直接涨了近一倍。这让我不得不开始考虑转移到私有云部署的 RSS 订阅工具。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240213213108000-50f6b33da050d4e53b0567cc8df75954.avif" alt="2024-02-13-21-31-08-Screenshot_20240207-012352_Original"&gt;&lt;/p&gt;
&lt;h1 id="试用-freshrss-和-miniflux"&gt;试用 FreshRSS 和 Miniflux&lt;/h1&gt;
&lt;p&gt;在尝试了 FreshRSS 和 Miniflux 之后，我发现 FreshRSS 存在过滤规则保存后为空的问题，另外全文抓取也需要更多更复杂的配置，不如 Miniflux 稳定和简单。最终，我决定保留 Miniflux。&lt;/p&gt;
&lt;h1 id="miniflux-的优势"&gt;Miniflux 的优势&lt;/h1&gt;
&lt;p&gt;Miniflux 是用 Go 语言实现的，拥有极简的 WebUI，占用系统资源较少，抓取能力出色。它支持根据订阅源的更新频率定制抓取时间间隔，还支持多种 Web 服务的集成，如我在用的 Readwise Reader。我选择使用 Docker 将 Miniflux 部署到 NAS 中，经过几天的试用，稳定性令人满意。&lt;/p&gt;
&lt;h1 id="miniflux-的不足"&gt;Miniflux 的不足&lt;/h1&gt;
&lt;p&gt;尽管 Miniflux 在功能上满足了我的需求，但其 Web 界面过于简洁，不太适合我快速浏览大量订阅内容的工作流。为了解决这个问题，我在 macOS 上配合 NetNewsWire 使用 Miniflux，不过这个阅读器缺少多种视图等功能，只能算是差强人意。&lt;/p&gt;
&lt;h1 id="未来的选择"&gt;未来的选择&lt;/h1&gt;
&lt;p&gt;如果没有意外，我计划在本月底 Inoreader 订阅到期后，正式放弃使用它，转而全面拥抱 Miniflux。虽然这个决定伴随着对 Inoreader 的不舍，但我相信 Miniflux 能够为我提供一个更加经济、灵活且高效的 RSS 阅读体验。&lt;/p&gt;</description></item><item><title>Proxmox VE 备份指南</title><link>http://0x3f.org/posts/proxmox-ve-backup-guide/</link><pubDate>Tue, 06 Feb 2024 18:48:31 +0800</pubDate><guid>http://0x3f.org/posts/proxmox-ve-backup-guide/</guid><description>&lt;p&gt;在当今数据中心管理中，数据备份是确保业务连续性和灾难恢复的关键环节。即使是 Home Lab ，也需要保证重要数据的安全。Proxmox Virtual Environment (PVE) 提供了一个强大的平台来管理虚拟化基础设施，而 Proxmox Backup Server (PBS) 则是其官方推荐的备份解决方案。本文将详细介绍如何使用 PBS 对 Proxmox VE 的虚拟机或容器（Guest）和宿主机（Host）进行备份，以及如何设置自动化备份流程。&lt;/p&gt;
&lt;h1 id="guest-的备份"&gt;Guest 的备份&lt;/h1&gt;
&lt;h2 id="使用-pbs"&gt;使用 PBS&lt;/h2&gt;
&lt;p&gt;Proxmox Backup Server (PBS) 是一个功能强大的备份工具，它提供了多种备份选项，包括增量备份、加密备份、自动备份以及自动修剪等功能。这些功能使得 PBS 成为与 PVE 结合紧密的理想选择。&lt;/p&gt;
&lt;h3 id="优势"&gt;优势&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;增量备份&lt;/strong&gt;：只备份自上次备份以来发生变化的数据，节省存储空间和时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加密备份&lt;/strong&gt;：确保备份数据的安全性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动备份&lt;/strong&gt;：设置定时任务，无需手动干预。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动修剪&lt;/strong&gt;：自动清理旧的备份，保持存储空间的合理使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;与 PVE 结合紧密&lt;/strong&gt;：PBS 专为 PVE 设计，备份和恢复过程无缝对接。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="步骤"&gt;步骤&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安装 PBS&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LXC 方式&lt;/strong&gt;：创建一个 Debian 容器，然后添加 PBS 的源。这种方式轻量级，但 LXC 容器只能使用 RAW 格式的镜像。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISO 方式&lt;/strong&gt;：通过 PBS 官方 ISO 镜像创建虚拟机。这种方式限制较少，能适应更多硬件环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;创建 PBS 备份用户&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 PBS 中，进入 Configuration → Access Control → User Management 创建一个新用户，例如 &lt;code&gt;dataguard&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>榨干 Intel 核显潜能，让更多虚拟机用上显卡</title><link>http://0x3f.org/posts/guide-to-increasing-intel-graphics-aperture-size/</link><pubDate>Tue, 06 Feb 2024 12:30:40 +0800</pubDate><guid>http://0x3f.org/posts/guide-to-increasing-intel-graphics-aperture-size/</guid><description>&lt;p&gt;在虚拟化环境中，尤其是使用 Proxmox VE 或其他虚拟化平台时，有时我们需要增加 Intel 核显的显存孔径（Aperture Size），以便让更多虚拟机用上显卡的硬件加速。例如，我的 i5-8600t CPU 的核显是 UHD630 ，它的显存孔径被限制为 256M ，这只能提供一个 1200p 或两个 768p 的虚拟 GPU ，显然太少了。而当我们把这个值上调到 1024M ，就能获得更多或性能更高的虚拟 GPU 。&lt;/p&gt;
&lt;p&gt;这可以通过修改 BIOS 设置来实现，但通常主板 BIOS 不提供直接的选项来调整这个值。幸运的是，我们可以通过一些工具来间接修改这个设置。以下是详细的步骤：&lt;/p&gt;
&lt;h3 id="步骤-1-下载和主板上同版本的-bios"&gt;步骤 1: 下载和主板上同版本的 BIOS&lt;/h3&gt;
&lt;p&gt;首先，你需要从主板制造商的官方网站下载与你的主板型号相匹配的 BIOS 文件。确保下载的是与你的主板上安装的 BIOS 版本相同的文件，以便后续操作不会引发兼容性问题。&lt;/p&gt;
&lt;h3 id="步骤-2-使用-uefitool-打开-bios"&gt;步骤 2: 使用 UEFITool 打开 BIOS&lt;/h3&gt;
&lt;p&gt;接下来，你需要使用 &lt;a href="https://github.com/LongSoft/UEFITool"&gt;UEFITool&lt;/a&gt;，这是一个 UEFI 固件图像查看器和编辑器。下载并安装 UEFITool，然后使用它打开你下载的 BIOS 文件。&lt;/p&gt;
&lt;h3 id="步骤-3-搜索aperture-size"&gt;步骤 3: 搜索“aperture size”&lt;/h3&gt;
&lt;p&gt;在 UEFITool 中，打开搜索对话框并选择“Text”类型，然后输入“aperture size”进行搜索。搜索结果中可能会有多个匹配项。&lt;/p&gt;
&lt;h3 id="步骤-4-导出-body-并转换"&gt;步骤 4: 导出 Body 并转换&lt;/h3&gt;
&lt;p&gt;选择一个搜索结果，导出其 Body。然后，使用 &lt;a href="https://github.com/LongSoft/IFRExtractor-RS"&gt;IFRExtractor-RS&lt;/a&gt;，这是一个 Rust 实用程序，可以将 UEFI IFR 数据提取成人类可读的文本。运行 IFRExtractor-RS 并指定你刚刚导出的文件，它会生成一个文本文件。&lt;/p&gt;</description></item><item><title>GVT-g 配置指南：实现多虚拟机共享 Intel 核显硬件加速</title><link>http://0x3f.org/posts/guide-to-configuring-gvt-g-graphics-acceleration/</link><pubDate>Tue, 06 Feb 2024 11:25:58 +0800</pubDate><guid>http://0x3f.org/posts/guide-to-configuring-gvt-g-graphics-acceleration/</guid><description>&lt;p&gt;Proxmox Virtual Environment（PVE）是一个功能强大的开源虚拟化管理平台。它允许用户在单个主机上运行多个虚拟机，每个虚拟机都可以拥有自己的操作系统。为了进一步提升虚拟机的性能，特别是对于那些需要图形处理能力的应用，我们可以通过配置 Intel® Graphics Virtualization Technology –g (GVT-g) 来实现。GVT-g 是一种硬件辅助的虚拟化技术，它允许虚拟机直接访问宿主机的图形处理单元（GPU），从而提高图形性能。本文将详细介绍如何在 PVE 中为 Intel 核显开启 GVT-g 。&lt;/p&gt;
&lt;p&gt;本文环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;操作系统：PVE 8.0&lt;/li&gt;
&lt;li&gt;CPU： Intel Core i5-8600t&lt;/li&gt;
&lt;li&gt;核显：UHD630&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="步骤-1-修改-grub-配置"&gt;步骤 1 ：修改 GRUB 配置&lt;/h3&gt;
&lt;p&gt;首先，我们需要确保 GRUB 引导加载器在启动时启用了必要的参数。打开&lt;code&gt;/etc/default/grub&lt;/code&gt;文件，并找到&lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt;行。添加以下参数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;quiet intel_iommu=on iommu=pt i915.enable_gvt=1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这将启用 Intel IOMMU（Input/Output Memory Management Unit）和 GVT-g 。保存文件后，运行以下命令来更新 GRUB 配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-grub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="步骤-2-添加内核模块"&gt;步骤 2 ：添加内核模块&lt;/h3&gt;
&lt;p&gt;接下来，我们需要确保 PVE 在启动时加载必要的内核模块。编辑&lt;code&gt;/etc/modules&lt;/code&gt;文件，添加以下模块：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vfio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vfio_iommu_type1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vfio_pci
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vfio_virqfd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kvmgt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果你之前因为配置直通核显而在&lt;code&gt;/etc/modprobe.d/pve-blacklist.conf&lt;/code&gt;中屏蔽了显卡驱动，现在需要解除屏蔽。这可以通过注释掉或删除相关行来实现。&lt;/p&gt;</description></item><item><title>Homelab 升级记：从 Unraid 到 Proxmox VE 的平滑过渡</title><link>http://0x3f.org/posts/a-smooth-transition-from-unraid-to-pve/</link><pubDate>Mon, 05 Feb 2024 22:22:57 +0800</pubDate><guid>http://0x3f.org/posts/a-smooth-transition-from-unraid-to-pve/</guid><description>&lt;p&gt;最近，我对我的 Homelab 进行了一次重大调整，从 Unraid 迁移到了 Proxmox VE（PVE），并用它实现了对 Unraid 的虚拟化，这一转变不仅提高了系统的稳定性、灵活性，还带来了一系列令人惊喜的改进。在这篇文章中，我将分享这次调整的动机、硬件升级以及软件配置的详细过程。&lt;/p&gt;
&lt;h1 id="动机解耦虚拟机与-unraid"&gt;动机：解耦虚拟机与 Unraid&lt;/h1&gt;
&lt;p&gt;我决定将虚拟机从 Unraid 中分离出来，这样做的目的是为了减轻 Unraid 重启时对整个网络环境的影响，降低磁盘阵列卡住的风险，并加速 Unraid 的重启过程。&lt;/p&gt;
&lt;p&gt;此外，这样的调整也使得使用 Proxmox Backup Server (PBS) 进行备份变得更加方便，减少了对 Unraid 缓存盘的占用，并优化了硬盘的休眠策略，减少了不必要的唤醒次数。&lt;/p&gt;
&lt;p&gt;最后，减少虚拟化嵌套层数，简化了架构，提高了整体效率。&lt;/p&gt;
&lt;h1 id="硬件升级"&gt;硬件升级&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;机箱改造：&lt;/strong&gt; 为了适应新的硬件配置，我用角磨机切掉了蜗牛星际机箱 B 款的横梁，因为它挡住了 PCIe 插槽。这一小小的改动为后续的硬件安装提供了空间。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240205224047000-0dc50a9a0eae412f122797fcab30da73.avif" alt="2024-02-05-22-40-47-IMG_1058"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240205224235000-dca7c6141a55e0e809aebf3522c14687.avif" alt="2024-02-05-22-42-35-DSC00141"&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;主板与扩展卡：&lt;/strong&gt; 主板只有一个 M.2 插槽，我选择在这里安装了 PVE。为了加装第二款 NVME 固态硬盘，我购买了 PCIe 转 M.2 扩展卡，将 Unraid 的缓存盘插到了这个扩展卡上。小火炉铠侠 RC10 在加装了扩展卡附带的散热片后降温效果显著，目测温度下降了大约 15℃，Unraid 系统再也没有出现过报警。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240220211519000-b74439897dda4d7bb5d007ebb189bd21.avif" alt="2024-02-20-21-15-19-IMG_1203"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240220211707000-c1b1b9b5ee67eb7a86f87407a567c232.avif" alt="2024-02-20-21-17-07-1E419BB6-4057-41B4-B7A5-6F3033154257_4_5005_c"&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;视频采集卡：&lt;/strong&gt; 为了在没有额外显示器的情况下管理 Homelab ，我购买了视频采集卡，并配合 iPad 使用，作为临时显示器。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240205232026000-9bcd2ed7eeced5a2fe814e03dcab03d9.avif" alt="2024-02-05-23-20-26-IMG_1079"&gt;&lt;/p&gt;
&lt;h1 id="软件配置"&gt;软件配置&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;直通设备：&lt;/strong&gt; 在 PVE 中，我将 Unraid 系统 U 盘、Sata 控制器、外置硬盘以及 NVME 缓存盘直通（passthrough）给了 Unraid 虚拟机。这样做的好处是，仍然使用 Unraid 作为 NAS 系统管理所有存储资源，并继续使用 Unraid 优秀的应用社区。同时把主板的第二块网卡做了直通，防止 NAS 吞吐量较大时影响访问宿主机及其它客户机的稳定性。&lt;/p&gt;</description></item><item><title>我的家庭数据备份方案</title><link>http://0x3f.org/posts/my-homelab-backup-strategy/</link><pubDate>Wed, 31 Jan 2024 20:02:08 +0800</pubDate><guid>http://0x3f.org/posts/my-homelab-backup-strategy/</guid><description>&lt;p&gt;在这个数字化时代，数据安全比以往任何时候都更加重要。无论是个人生活还是工作，我们都需要一个可靠的备份方案来确保数据的安全。今天，我想分享我的家庭数据备份方案，它不仅涵盖了我所有的虚拟机、容器和配置数据，还包括了 NAS 上的重要文件，如照片、密码、笔记和待办事项。这个方案遵循了著名的 3-2-1 备份策略，并且通过精心选择的备份工具，确保了数据的安全性和高效性。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240131204032000-81dba599d77a03eb89e682de235b0bde.avif" alt="2024-01-31-20-40-32-_d0c7d6aa-d312-4749-89ce-d3996aaaddf6"&gt;&lt;/p&gt;
&lt;h3 id="数据种类"&gt;数据种类&lt;/h3&gt;
&lt;p&gt;首先，让我们来了解我需要备份的数据种类。我有两个 PVE（Proxmox Virtual Environment）宿主机，上面运行着多个虚拟机和容器。这些虚拟机和容器包含了我所有的工作和个人项目。为了备份这些数据，我选择了 PBS（Proxmox Backup Server）作为备份存储。同时，我还使用 proxmox-backup-client 将 PVE 的配置数据也备份到 PBS 。&lt;/p&gt;
&lt;p&gt;除了虚拟机和容器，我的 NAS 上还存储着许多重要数据，包括家庭照片、密码管理器的数据库、个人笔记以及待办事项列表。这些数据对我来说同样重要，因此我也将它们纳入了备份计划。&lt;/p&gt;
&lt;h3 id="备份策略"&gt;备份策略&lt;/h3&gt;
&lt;p&gt;我遵循的备份策略是 3-2-1 原则，即至少有三份备份，存储在两种不同的媒介上，且至少有一份在其他地方。这个策略可以有效地防止数据丢失。&lt;/p&gt;
&lt;h4 id="3-2-1策略的具体实现"&gt;3-2-1策略的具体实现&lt;/h4&gt;
&lt;p&gt;为了实现这一策略，我部署了两个 Kopia 实例，并行运行，分别将数据备份到阿里云盘和我的移动硬盘。这样做的原因是 KopiaUI 目前只支持同时连接一个仓库，而并行备份可以确保即使上游备份出现问题，也不会影响下游的备份进程。&lt;/p&gt;
&lt;h4 id="为什么选择并行而不是串行"&gt;为什么选择并行而不是串行&lt;/h4&gt;
&lt;p&gt;串行备份可能会导致一个问题：如果上游的备份过程中出现错误，那么这个错误会被传递到下游的备份。通过并行备份，我们可以避免这种情况，确保每个备份都是独立的。&lt;/p&gt;
&lt;h4 id="备份工具的选择"&gt;备份工具的选择&lt;/h4&gt;
&lt;p&gt;在选择备份工具时，我考虑了以下几个标准：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;支持本地和云备份&lt;/strong&gt;：这样可以确保数据在本地和远程都有备份。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持增量备份&lt;/strong&gt;：只备份自上次备份以来发生变化的数据，节省时间和存储空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持压缩和加密&lt;/strong&gt;：保护数据安全的同时，减少存储需求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持将备份数据分割成一定大小&lt;/strong&gt;：这对于远程备份尤其有用，可以提高小文件的上传速度，降低大文件上传失败的风险。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持定时备份&lt;/strong&gt;：自动化的定时备份可以确保数据始终是最新的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;稳定性和易用性&lt;/strong&gt;：工具需要稳定运行，并且用户界面友好，易于操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在对比了多个备份工具后，我选择了 Kopia 和 Duplicati 。以下是它们的优缺点对比：&lt;/p&gt;
&lt;h5 id="duplicati"&gt;Duplicati&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;易于部署，通过 Docker 部署非常简单。&lt;/li&gt;
&lt;li&gt;用户界面友好，易于操作。&lt;/li&gt;
&lt;li&gt;支持同时连接多个仓库。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 .Net 实现，可能会占用更多的系统资源。&lt;/li&gt;
&lt;li&gt;有关于稳定性的传闻，尽管这可能因环境而异。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="kopia"&gt;Kopia&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;稳定性的负面反馈较少，运行效率高。&lt;/li&gt;
&lt;li&gt;占用资源相对较少，对系统的影响小。&lt;/li&gt;
&lt;li&gt;用户界面简洁，易于理解。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;部署和上手难度较高，相关资料较少，官方文档不够详尽。&lt;/li&gt;
&lt;li&gt;不支持同时连接多个仓库，这在某些情况下可能会造成不便。&lt;/li&gt;
&lt;li&gt;高级功能通常需要通过命令行实现，对于不熟悉命令行的用户来说可能不够友好。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="结语"&gt;结语&lt;/h3&gt;
&lt;p&gt;通过这样的备份方案，我可以确保我的数据在多种情况下都能得到保护。无论是硬件故障还是意外删除，我都有办法恢复我的数据。这给了我极大的安心，让我可以专注于我的工作和家庭生活，而不必担心数据安全问题。希望我的分享能为你的家庭数据备份提供一些启示。&lt;/p&gt;</description></item><item><title>猫眼铃铛，我的梦中情铃</title><link>http://0x3f.org/posts/highly-recommend-the-cat-eye-bell/</link><pubDate>Mon, 22 Jan 2024 22:34:37 +0800</pubDate><guid>http://0x3f.org/posts/highly-recommend-the-cat-eye-bell/</guid><description>&lt;p&gt;蚂蚁腿走大路，装了个全银色杠杆撞击式的车铃也够用，一半也算是配合全银车把，起个装饰作用。Jifo 走街串巷，骑了两次胡同就感觉原装车铃用着难受了。&lt;/p&gt;
&lt;p&gt;猫眼这款横拨铃铛（PB-1000P），拨一下响两声，声音清脆，音量不小，有二八大杠六厘米大铃的灵魂和大行原装车铃的风格身量，非常符合我对 Jifo 优化体验、尽量保留原车风格的改装思路。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240122223638000-b1477b1d52aece22ace7dbac7195beff.avif" alt="2024-01-22-22-36-38-IMG_1043"&gt;&lt;/p&gt;
&lt;p&gt;到手后发现，作为一个左手铃，铃体中轴是靠后的，大拇指拨动铃柄，其它四指要脱离刹把，效率不高，也不安全。试了几种安装方位，最后感觉左手吊装是最优方案，只需要食指自然下移就能搭在铃柄上，其它手指握住车把、刹把不用动，既安全、效率又高，而且 Jifo 把横较窄，车铃正装的话左侧一半把横几乎就搭载不了任何东西了，吊装之后铃铛被刹把遮挡，反而既能节省空间又让视觉效果更简洁。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240122223739000-8147a5210364d4dc36c83fbab658f402.avif" alt="2024-01-22-22-37-39-IMG_1034"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240122223810000-2128b35ac7a15bed044f87825db619a4.avif" alt="2024-01-22-22-38-10-IMG_1044"&gt;&lt;/p&gt;
&lt;p&gt;如果一定要正装的话，可以考虑 PB-1100P ，中轴居中，姆指更好够到。怪不得铃体相同的 PB-1000P 便宜不少，应该是为了兼容左手指拨所做的妥协，所幸 Jifo 这车也很特别，负负得正了属于是。&lt;/p&gt;
&lt;p&gt;出车试铃效果不错，连拨两下响铃四声，既过瘾，让行人避让的效果又好，唯一不足是铃声向下，于音量有损。&lt;/p&gt;</description></item><item><title>Jifo 前刹的改造之路：彰星夹器的优缺点</title><link>http://0x3f.org/posts/the-road-to-modifying-jifos-front-brake/</link><pubDate>Mon, 15 Jan 2024 19:13:10 +0800</pubDate><guid>http://0x3f.org/posts/the-road-to-modifying-jifos-front-brake/</guid><description>&lt;p&gt;大行 Jifo 的原装前刹是单轴夹器，刹车力较弱，和后刹刹车力不一致会导致急刹车时发生甩尾，不安全。所以从这个车型在 12 年上市以后，就一直有人在探索前刹的改装方案。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240115201620000-05158d1dfd5ac42f0a751ba6dc2dd4ee.avif" alt="2024-01-15-20-16-20-e3e356bd402bd5fcb4157225c29f5966"&gt;&lt;/p&gt;
&lt;p&gt;Jifo 原装夹器的行程较短（约 51mm），左侧拉线，使用 51mm （裸露）长度的螺杆和普通螺母安装，想找到满足这些条件的双轴夹器是不可能的，不然十几年过去了，也不至于没有一个完美的改装案例。&lt;/p&gt;
&lt;p&gt;考虑了两种改造思路。&lt;/p&gt;
&lt;p&gt;一是用 Jifo 的升级版 eezz 的前夹器。从某种程度上说，这几乎是最完美的方案——行程合适、左侧拉线、双轴，但唯一的问题是只有黑色，需要脱漆、抛光并解决氧化的问题，而且物稀价贵，时间和物料成本较高。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240115193539000-b1ca47d5d132baba0eefd23a6d061b33.avif" alt="2024-01-15-19-35-39-12_161782_e4b20df32aa0866"&gt;&lt;/p&gt;
&lt;p&gt;再就是用普通夹器改造。目前只能找到极少的左侧拉线的双轴夹器，但因为行程不合适，用不了。只能退而求其次，从右侧拉线的产品里挑。之前有人用彦豪 539 改过，但是不知道为什么，彦豪的夹器很少单卖，量少而且价格很高。所幸最后找到了彰星的夹器，做工用料都很好，而且造型美观。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240115194324000-726b6a3c2c2ddb61316f78978e28d8f1.avif" alt="2024-01-15-19-43-24-DSC00137"&gt;&lt;/p&gt;
&lt;p&gt;另买了个垃圾夹器，拆螺杆、螺母和垫片用。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240115194436000-8d53f113a526f7ae3a4d683c79da36e4.avif" alt="2024-01-15-19-44-36-DSC00136"&gt;&lt;/p&gt;
&lt;p&gt;改装很成功，CP 值、刹车力和手感都有很大提升。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240115194551000-ae402e05a49659e2d4e048514ad8f5f1.avif" alt="2024-01-15-19-45-51-DSC00139"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20240115194603000-1f2b6fa1629587aa17ed318770d6b539.avif" alt="2024-01-15-19-46-03-DSC00140"&gt;&lt;/p&gt;
&lt;p&gt;但是折叠时必须小心翼翼地找刁钻的角度，否则容易撞到夹器，折叠后夹器和连接杆会因有干涉而产生轻微的损伤。&lt;/p&gt;
&lt;p&gt;所以想要完美地折叠，只能用左侧拉线的夹器，彰星的这款如果有左侧版本就太完美了，可惜难遂我愿，现在市面上的夹器几乎全是右侧拉线的，只能徒叹奈何了。&lt;/p&gt;
&lt;p&gt;总之这次的改造也能用，但权衡之下，我觉得折叠的流畅度更重要，何况原装的夹器也不是完全不能用，换装永杰 470 刹车皮之后制动力有一定的提升。暂时先这样吧，改造过的夹器留作备份了。&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;2024-04-29 现在有了&lt;a href="http://0x3f.org/posts/the-end-of-road-to-modifying-jifos-front-brake/"&gt;新的进展&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>轻松管理 Docker 下的 MariaDB 错误日志：重定向到日志控制台和日志轮转</title><link>http://0x3f.org/posts/steps-to-implement-redirection-and-rotation-for-error-logs-of-docker-deployed-mariadb/</link><pubDate>Mon, 15 Jan 2024 16:48:09 +0800</pubDate><guid>http://0x3f.org/posts/steps-to-implement-redirection-and-rotation-for-error-logs-of-docker-deployed-mariadb/</guid><description>&lt;p&gt;本文旨在通过把 MariaDB 的错误日志重定向到 Docker 的错误控制台以实现通过 Loki 收集日志，并使用日志轮转控制日志文件大小。&lt;/p&gt;
&lt;h1 id="指定固定的日志文件名"&gt;指定固定的日志文件名&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[mariadb]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;log_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/config/databases/mariadb.err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h1 id="把容器中的错误日志重定向到-docker-日志控制台"&gt;把容器中的错误日志重定向到 Docker 日志控制台&lt;/h1&gt;
&lt;p&gt;在容器的环境变量中添加以下内容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;DOCKER_MODS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;lscr.io/linuxserver/mods:universal-stdout-logs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;LOGS_TO_STDOUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/config/databases/mariadb.err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h1 id="设置-mariadb-的-rootlocalhost-用户的鉴权方式"&gt;设置 MariaDB 的 root@localhost 用户的鉴权方式&lt;/h1&gt;
&lt;p&gt;创建 root@localhost 用户：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;VIA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;unix_socket&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;或更改已存在的 root@localhost 用户的鉴权方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;VIA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;unix_socket&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h1 id="受权-reload-给-rootlocalhost-用户"&gt;受权 RELOAD 给 root@localhost 用户&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RELOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h1 id="配置-logrotate"&gt;配置 logrotate&lt;/h1&gt;
&lt;p&gt;在宿主机创建 &lt;code&gt;/etc/logrotate.d/mariadb&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/mnt/user/appdata/mariadb/databases/mariadb.err &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; su nobody users
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; missingok
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; create &lt;span class="m"&gt;660&lt;/span&gt; nobody users
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; notifempty
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; daily
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; minsize 1M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; maxsize 100M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rotate &lt;span class="m"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dateext
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dateformat .%Y-%m-%d-%H-%M-%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; compress
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; delaycompress
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sharedscripts
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; olddir ../archive/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; createolddir &lt;span class="m"&gt;770&lt;/span&gt; nobody users
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; postrotate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# just if mysqld is really running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; docker &lt;span class="nb"&gt;exec&lt;/span&gt; mariadb &lt;span class="nb"&gt;test&lt;/span&gt; -x /usr/bin/mysqladmin &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; docker &lt;span class="nb"&gt;exec&lt;/span&gt; mariadb /usr/bin/mysqladmin ping &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; docker &lt;span class="nb"&gt;exec&lt;/span&gt; mariadb /usr/bin/mysqladmin --local flush-error-log &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; flush-engine-log flush-general-log flush-slow-log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; endscript
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;可通过以下命令测试效果：&lt;/p&gt;</description></item><item><title>优化 BT 下载速度的方法</title><link>http://0x3f.org/posts/how-to-optimize-bt-download-speed/</link><pubDate>Wed, 15 Nov 2023 22:30:47 +0800</pubDate><guid>http://0x3f.org/posts/how-to-optimize-bt-download-speed/</guid><description>&lt;h1 id="映射下载机端口到外网"&gt;映射下载机端口到外网&lt;/h1&gt;
&lt;h2 id="申请公网-ip"&gt;申请公网 IP&lt;/h2&gt;
&lt;p&gt;找宽带客服给分配公网 IP 地址。现在一般是给城域网地址了吧，不过也能用。&lt;/p&gt;
&lt;h2 id="配置光猫桥接"&gt;配置光猫桥接&lt;/h2&gt;
&lt;p&gt;找宽带客服提要求，会安排维修人员上门处理。&lt;/p&gt;
&lt;h2 id="配置路由器"&gt;配置路由器&lt;/h2&gt;
&lt;h3 id="映射下载机端口"&gt;映射下载机端口&lt;/h3&gt;
&lt;p&gt;把 BT 客户端所在的 IP 和端口映射到外网：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231115231555000-af657d4988ae78227f9890d81a790b65.avif" alt="2023-11-15-23-15-55-IMG_0699"&gt;&lt;/p&gt;
&lt;h3 id="打开-upnp"&gt;打开 uPnP&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231115231647000-d903211f0e21507357c7c3f6662953ed.avif" alt="2023-11-15-23-16-47-mac_20231106165924"&gt;&lt;/p&gt;
&lt;h2 id="配置-bt-客户端"&gt;配置 BT 客户端&lt;/h2&gt;
&lt;p&gt;指定固定的端口号，和前面路由器里的端口映射对应：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231115232327000-fe2f9d0f28e4622c09bb143605f77835.avif" alt="2023-11-15-23-23-27-mac_20231106165358"&gt;&lt;/p&gt;
&lt;h1 id="更新-trackers"&gt;更新 Trackers&lt;/h1&gt;
&lt;p&gt;从下面网址获取最新的 tracker 服务器，保存到 BT 客户端里：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://trackerslist.com/best.txt"&gt;https://trackerslist.com/best.txt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231115232411000-0d78a98d0d7b9286695dbce7741e8a53.avif" alt="2023-11-15-23-24-11-mac_20231106165512"&gt;&lt;/p&gt;
&lt;h1 id="其它问题"&gt;其它问题&lt;/h1&gt;
&lt;h2 id="alternative-rate-limits"&gt;Alternative Rate Limits&lt;/h2&gt;
&lt;p&gt;qBittorrent 有个可选限速的配置，默认是 10KiBps ，如果误点了状态栏的按钮可能会启用这个配置，导致速度上不去。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231115232450000-85bcd58c1245d921947def223e5acf63.avif" alt="2023-11-15-23-24-50-IMG_0632"&gt;
&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231115232451000-54a4ebc44af2f7fb34eeeda6fbe0137a.avif" alt="2023-11-15-23-24-51-mac_20231106165553"&gt;&lt;/p&gt;</description></item><item><title>8￥包邮的帆布包，实现了我对骑行收纳的所有想象</title><link>http://0x3f.org/posts/experience-on-several-bicycle-saddle-bags/</link><pubDate>Tue, 14 Nov 2023 22:18:16 +0800</pubDate><guid>http://0x3f.org/posts/experience-on-several-bicycle-saddle-bags/</guid><description>&lt;p&gt;以前一直只用 1L 的车头包，想多带点东西时就会觉得很局促，而且折叠之前要先把包里的东西拿出来，多有不便。最近试用了几款尾包，分享一下我的使用感受。&lt;/p&gt;
&lt;h1 id="洛克兄弟尾包美而不便"&gt;洛克兄弟尾包，美而不便&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223257000-997a2dbc3d8eb8423cf4d037c7b79451.avif" alt="2023-11-14-22-32-57-DSC00106"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223300000-00ba3dc99b6517a508e3ec95bb9e62f1.avif" alt="2023-11-14-22-33-00-DSC00107"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223303000-8de29770c7f66573187b8730e17c0935.avif" alt="2023-11-14-22-33-03-DSC00108"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223305000-fa9052889f98abc0d655eb13933028ee.avif" alt="2023-11-14-22-33-05-DSC00109"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223307000-541d7fee1c23c122d686e72098094b08.avif" alt="2023-11-14-22-33-07-DSC00110"&gt;&lt;/p&gt;
&lt;p&gt;最初被洛克兄弟这款 0.73L 的尾包吸引是因为它的外形，增一分太大，减一分太小，线条流畅而不古板，点缀不多又不寒酸，突出一个恰到好处。&lt;/p&gt;
&lt;p&gt;包的内部收纳设计尚可，内壁两侧各有一个夹层，兼顾了零碎的收纳和保留了较大的剩余空间。拉开底部的拉锁还可以进一步扩展容量，这一点考虑得很周到。如果开口处能再加一个夹层就更好了。&lt;/p&gt;
&lt;p&gt;装车后整体也比较满意，但有个使用上较为不便的问题：挑座垫。它的开口上沿紧贴座垫，如果座垫后缘稍长就会压住开口，再加上这款包用的防水拉锁阻尼较大，所以拉的时候很不方便。在我另外一个后缘较短的座垫上，这个问题会得到缓解。&lt;/p&gt;
&lt;p&gt;此外，包的后部可以挂尾灯，这点很好。&lt;/p&gt;
&lt;p&gt;考虑之后还是退了，毕竟一个提供方便的东西，如果用起来有感到不便的地方，还是有点本末倒置了。&lt;/p&gt;
&lt;h1 id="inbike-尾包很好除了颜值"&gt;INBIKE 尾包很好，除了颜值&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223716000-3ce816aeb885e8c2f32bb22bdeb47c7b.avif" alt="2023-11-14-22-37-16-DSC00111"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223718000-b662e539cabdac7990ac3746e068ddbc.avif" alt="2023-11-14-22-37-18-DSC00112"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223721000-d76fc27d028212efffc9511efdb5ff0c.avif" alt="2023-11-14-22-37-21-DSC00113"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223723000-f2ff8802434084957012efca8737fdcf.avif" alt="2023-11-14-22-37-23-DSC00114"&gt;&lt;/p&gt;
&lt;p&gt;INBIKE 的这款尾包在材质和工艺上和洛克兄弟的很像。由造型的原因，容量明显大于后者，开口也不易被座垫遮挡，加上它的防水拉锁阻尼没那么大，所以相对来说更容量拉开。&lt;/p&gt;
&lt;p&gt;内部收纳设计较为简单，除了开口处有一个夹层外，再无空间的划分，也算兼顾了小物价的收纳并提供了更大的一体空间。&lt;/p&gt;
&lt;p&gt;包的后盖也提供了挂载尾灯的位点。&lt;/p&gt;
&lt;p&gt;在相似的材质、工艺下，这款包的价格比洛克兄弟那款便宜三分之一左右，而容量更大，使用更方便，确实是个很有性价比的选择。唯一让我不满意的地方是造型比较呆板，点缀有点俗气。&lt;/p&gt;
&lt;h1 id="迪卡侬尾包目标明确针对性很强"&gt;迪卡侬尾包，目标明确，针对性很强&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223918000-dbac7457b6bc942eb26bf1b74521bdf0.avif" alt="2023-11-14-22-39-18-DSC00119"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223921000-91923a854c6128948d2c543c050df5a5.avif" alt="2023-11-14-22-39-21-DSC00120"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223924000-00e6a52d3de1e3a77cb4c57fa0e1445c.avif" alt="2023-11-14-22-39-24-DSC00121"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114223926000-fa278a08f83e736bc98e4594665e98d1.avif" alt="2023-11-14-22-39-26-DSC00122"&gt;&lt;/p&gt;
&lt;p&gt;迪卡侬的这款尾包容量不大（0.6L），内部分割为上下两层，下层有三个夹层，适合带点修车工具和备胎，想带点别的随身物品就不够用了，所以目标很明确，针对性很强。&lt;/p&gt;
&lt;p&gt;此外，造型好看，开口位于下方、且没有采用防水拉锁，很方便存取物品，外表覆盖大面积反光涂层，夜骑很亮。&lt;/p&gt;
&lt;p&gt;总之，适合专业骑行，不适合日常使用。&lt;/p&gt;
&lt;h1 id="犀牛尾包轻且防水没了"&gt;犀牛尾包，轻且防水……没了&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224110000-f5498f0569a76a78ab03f4f8a7fae644.avif" alt="2023-11-14-22-41-10-DSC00123"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224112000-7644189be705eee423714e5278bf963d.avif" alt="2023-11-14-22-41-12-DSC00124"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224115000-feabe501e92ab6db5c39c09f910e0f1e.avif" alt="2023-11-14-22-41-15-DSC00125"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224117000-38443784b1e390f72a8aa15d7099d4d3.avif" alt="2023-11-14-22-41-17-DSC00126"&gt;&lt;/p&gt;
&lt;p&gt;犀牛的这款尾包为了追求极致的轻量，减掉了一切可以减掉的东西，没有分割内部收纳空间、没有尾灯挂载位点，把重量压缩到了 70g 附近。包体材料是 600D TPU ，使用防水拉锁，看起来防水效果应该很不错。&lt;/p&gt;
&lt;p&gt;但它的内部什么夹层、分隔都没有，就是一整块收纳空间，稍大点的东西放不下，小东西堆在一起不好取用。&lt;/p&gt;
&lt;h1 id="8包邮的帆布包完美满足我骑行收纳需求"&gt;8￥包邮的帆布包，完美满足我骑行收纳需求&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224254000-d86c700535a0a161bb97306d71d0696b.avif" alt="2023-11-14-22-42-54-DSC00115"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224256000-e0f0810975ca22feb355e0ad0ccb1e3e.avif" alt="2023-11-14-22-42-56-DSC00116"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224258000-51eaf199593bb45d1dce32d8ab89fef2.avif" alt="2023-11-14-22-42-58-DSC00117"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231114224300000-dd97f4e7657b39367286752c7ac44530.avif" alt="2023-11-14-22-43-00-DSC00118"&gt;&lt;/p&gt;
&lt;p&gt;此前试用的几款正经的尾包，要么使用不方便，要么收纳空间太小，而且它们都太正经了，和我这菜车的气质不搭嘎。我对尾包的所有想象在于容量大、使用方便、休闲风，直到偶然发现这个战术回收包，这不就是我的梦中情包么？&lt;/p&gt;
&lt;p&gt;用了一段时间，效果非常理想。外侧三个夹层，加上包内超大收纳空间，平时带一些随身物品绰绰有余，偶尔买点干果零食甚至直接往里一塞就行。&lt;/p&gt;
&lt;p&gt;重点是，只要8块包邮！同等容量的某网红车包价格是它的7倍，而收纳设计还更简陋。&lt;/p&gt;
&lt;p&gt;鲁迅说过，要啥自行车！&lt;/p&gt;</description></item><item><title>重新发售的翰林阅 Read6 Pro 使用体验</title><link>http://0x3f.org/posts/hands-on-the-new-hanlinyue-read6-pro/</link><pubDate>Mon, 02 Oct 2023 17:03:46 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-the-new-hanlinyue-read6-pro/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231002170857000-744078fdb8060f143f5d3e39113787ca.avif" alt="2023-10-02-17-08-57-DSC00101"&gt;&lt;/p&gt;
&lt;p&gt;之前&lt;a href="http://0x3f.org/posts/hands-on-hanlinyue-read6-pro/"&gt;试用过第一次发售的版本&lt;/a&gt;，体验非常糟糕。前不久发现翰林阅又发了预售通知，原来经过上次哀鸿遍野的退货潮，他们迭代了产品重新上市了。&lt;/p&gt;
&lt;h1 id="新的工业设计比之前好看"&gt;新的工业设计比之前好看&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;外壳正面由原来内嵌到背盖里改成了覆盖式，隐藏了边缝。&lt;/li&gt;
&lt;li&gt;外壳边缘和屏幕边缘的下凹处都有倒角，视觉效果圆润且触感很好。&lt;/li&gt;
&lt;li&gt;品牌标识由原来的深色大字改成了浅色小字，看起来和谐多了。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="做工比之前好了很多但还是不够好"&gt;做工比之前好了很多，但还是不够好&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;边缝比以前小多了，但是有的边角还是有缝，按压没有咔哒声了，但能看到轻微的跷跷板现象。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="显示效果进步有限"&gt;显示效果进步有限&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;屏幕的显示效果好了很多，墨迹不均匀的问题没有了，但还是没解决残影问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231002171120000-97fa7d68f3d33f9bbed814e99845dc30.avif" alt="2023-10-02-17-11-20-DSC00100"&gt;&lt;/p&gt;
&lt;h1 id="背光的灯箱效果没解决"&gt;背光的灯箱效果没解决&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;背光不像之前那样没法看了，但还是泛蓝、有灯箱效果，和文石 Poke5S 一样，弱光下看起来很不舒服&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20231002171041000-afe786f24a32a85360fff5b37095b9bf.avif" alt="2023-10-02-17-10-41-DSC00103"&gt;&lt;/p&gt;
&lt;h1 id="系统简陋优化很差"&gt;系统简陋，优化很差&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;连输入法的设置都没有，无法使用双拼，在电子墨水屏幕上用全拼体验太差了。&lt;/li&gt;
&lt;li&gt;在微信读书中输入笔记时，光标的闪动会每隔几秒触发一次屏幕全刷新，体验很差。&lt;/li&gt;
&lt;li&gt;和之前一样，看着挺好的配置，操作一点都不跟手。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="总结"&gt;总结&lt;/h1&gt;
&lt;p&gt;更新后的新机器做工好了很多，边缘的倒角和背盖的斜坡设计使得握持感比我现在用的墨案 Air 好很多，如果不是背光太影响阅读体验以及系统优化太差，它应该是个非常符合我需求的阅读器。&lt;/p&gt;</description></item><item><title>首刷中国考古博物馆</title><link>http://0x3f.org/posts/my-first-visit-to-the-national-archaeological-museum-of-china/</link><pubDate>Wed, 27 Sep 2023 23:26:55 +0800</pubDate><guid>http://0x3f.org/posts/my-first-visit-to-the-national-archaeological-museum-of-china/</guid><description>&lt;p&gt;抢票的过程令人很不愉快，各种报错，拼命地点了一通后，终于抢到了当天和周三的票，每天生成了好几单，说明当时系统有重复下单的问题（今天再看的时候已经改成点完按钮以后、响应返回之前禁止点击了）。结果当天下午过去后刷不进去，再看的时候发现当天的订单都不见了，只剩下周三的一个单。这种情况肯定是人为删了。跟我前后脚到场的也有一家人也是这种情况。工作人员说去查数据库，等了半天也没结果，正好维修人员来修宽带，我就回家了，不知道那家人后来进没进去。&lt;/p&gt;
&lt;p&gt;等到周三终于进去了。&lt;/p&gt;
&lt;p&gt;安保等级很高，到处都是工作人员。内部装修很好，基础设施完备，毕竟是新馆，因为每天限 500 个名额，人也不多，总体观展体验很好。展品很硬，有一些只在书和电视上看过的东西，像是赴了个多年的约会。赶上了下午三点的讲解，耗时一个半小时，听完正好清场，讲解员很辛苦也很专业，但我觉得讲得太浅，只是简介性质。一共四层，第一层主要是两具陪葬车马，二、三层是主要内容，四层偏近代。文创店在一层，东西一般，不少人在那买了本子到各展区盖章，觉得没什么意义，就没有做。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234035000-48eee4740ac9201cc341c2b4951fe7be.avif" alt="2023-09-27-23-40-35-IMG_0353"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234054000-2f0149cf08931fb789ae01d59457c57d.avif" alt="2023-09-27-23-40-54-IMG_0356"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234051000-8055377cd3a36c88c5bb63d6390f26b1.avif" alt="2023-09-27-23-40-51-IMG_0359"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234047000-96f8a42eb2fd009704528cb3ff2d6d76.avif" alt="2023-09-27-23-40-47-IMG_0362"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234049000-be4dbfa0133d57211174542c420fa799.avif" alt="2023-09-27-23-40-49-IMG_0360"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234044000-796db818e3eee4b7fb01b28c3e377532.avif" alt="2023-09-27-23-40-44-IMG_0364"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234042000-804eac8668c012daf388c63ff2ec1f3b.avif" alt="2023-09-27-23-40-42-IMG_0365"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230927234040000-4b534cce0a1063e43d1b60fd7025c648.avif" alt="2023-09-27-23-40-40-IMG_0366"&gt;&lt;/p&gt;</description></item><item><title>墨案 Air 的使用感受</title><link>http://0x3f.org/posts/hands-on-moaan-air/</link><pubDate>Tue, 12 Sep 2023 22:59:11 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-moaan-air/</guid><description>&lt;p&gt;经过一些对微信读书阅读器的尝试&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;，最终选择了墨案 Air。&lt;/p&gt;
&lt;p&gt;优点是屏幕显示和背光这两个核心指标过关。Carta 1200、300 PPI，文字的锐度不错，底色较白，背光比较自然，相对其它国产 6 寸阅读器来说更接近纸质书的效果，不会过度影响阅读的沉浸感。&lt;/p&gt;
&lt;p&gt;和文石 Poke5S 的对比：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230912231904000-d1c3b1e1de84b75917f910acef65a603.avif" alt="2023-09-12-23-19-04-DSC00095"&gt;&lt;/p&gt;
&lt;p&gt;抛开 212 的 PPI 不说，后者的背光在环境光强度较高的时候看着还行，但是弱光条件下明显泛蓝，调节暖色光也没有用，感觉冷光是冷光、暖光是暖光，而墨案 Air 的两色背光融合度好得多。&lt;/p&gt;
&lt;p&gt;不过，这都 2023 年了，国产阅读器在 Carta 1200 加持下的显示效果都比不过 6 年前的 Kindle Oasis 2 ，后者还是 Carta 1000 。如果不是有些书的特定版本只在微信读书上有，我才不在这些电子垃圾上花时间。&lt;/p&gt;
&lt;p&gt;缺点比较多。&lt;/p&gt;
&lt;p&gt;首先是反应慢，明显不跟手，和其它主要竞品比简直没眼看。不过，鉴于主要操作只有翻页，也就问题不大了。&lt;/p&gt;
&lt;p&gt;其次，残影明显。这算是国产阅读器的通病了。不过拿电子书阅读器看的一般都是纯文字的书，残影只在显示图片时严重影响观感，也算勉强可以接受。&lt;/p&gt;
&lt;p&gt;256 灰阶默认是关闭的，这很难理解，除非打开会有更大的问题，但我暂时没发现。打开后图片过渡更平滑，但依然看不到文石 Poke5S 能看到的阴影：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230912234427000-4d892682b2c04b15cf10ca292899a9ca.avif" alt="2023-09-12-23-44-27-DSC00096"&gt;&lt;/p&gt;
&lt;p&gt;此外还有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;屏幕盖板是塑料材质，需要注意刮花。&lt;/li&gt;
&lt;li&gt;做工一般，边缘有点割手。&lt;/li&gt;
&lt;li&gt;前黑后蓝有条纹，外观一般。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今年 6 寸国产阅读器还是没有让我很满意的，考虑到影响阅读体验的核心指标还说得过去，另外背面有弧度、握持感不错，先就它了。&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a href="http://0x3f.org/posts/hands-on-boox-poke5s/"&gt;文石 Poke5S 的使用感受&lt;/a&gt;&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;a href="http://0x3f.org/posts/hands-on-hanlinyue-read6-pro/"&gt;翰林阅 Read6 Pro 的使用感受&lt;/a&gt;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description></item><item><title>OmniFocus 插件 refine-task v1.0 小记</title><link>http://0x3f.org/posts/omnifocus-plugin-refine-task-v1-release-notes/</link><pubDate>Wed, 30 Aug 2023 22:05:59 +0800</pubDate><guid>http://0x3f.org/posts/omnifocus-plugin-refine-task-v1-release-notes/</guid><description>&lt;p&gt;&lt;a href="https://github.com/xbot/omnifocus-plugin-refine-task"&gt;refine-task&lt;/a&gt; 的功能非常简单，它为选中的任务打开一个输入框，将用户输入的内容作为新的任务内容保存，原来的任务内容会被挪到备注里：&lt;/p&gt;
&lt;video controls autoplay loop width="100%"&gt;
&lt;source src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/2023-08-30-22-04-08-Kapture 2023-08-30 at 19.33.05.mp4" type="video/mp4"&gt;
Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;我用快捷指令“&lt;a href="https://www.icloud.com/shortcuts/dd3a5d430a434d39aff4e3092e7abfee"&gt;收集 Tweet 到 OmniFocus&lt;/a&gt;”收集 tweets ，但是因为 tweet 内容较长，不方便 review 的时候快速了解为什么收集这条内容，所以我用快捷指令“&lt;a href="https://www.icloud.com/shortcuts/899467b735304519aa4b26b8c7756433"&gt;提炼 OmniFocus&lt;/a&gt;”利用 ChatGPT 提炼待办事项并复制到剪贴板，接着这个快捷指令会调用 refine-task 把条目原文移动到备注里并打开输入框由用户粘贴或者输入待办事项。&lt;/p&gt;</description></item><item><title>夏季厨余垃圾防腐防虫绝招</title><link>http://0x3f.org/posts/summer-kitchen-organic-waste-preservation-insect-prevention-tips/</link><pubDate>Sat, 26 Aug 2023 19:01:49 +0800</pubDate><guid>http://0x3f.org/posts/summer-kitchen-organic-waste-preservation-insect-prevention-tips/</guid><description>&lt;p&gt;做饭产生的湿垃圾，说多不多，说少不少，不想浪费垃圾袋，等快满了才扔。但是每次掀开桶盖都跟开盲盒似的，被各种难言的味儿熏一跟头，有几天吃水果比较多，打开桶盖跟天女散花一样，很多小虫子🪰。
疫情期间剩下不少酒精消毒液，最近灵机一动，每次饭后给厨余垃圾喷一点，几天下来既不生虫也没有怪味儿。🤪&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230826191023000-dca98d90f2d503b3a60d9d10ef6604f4.avif" alt="2023-08-26-19-10-23-IMG_0264"&gt;&lt;/p&gt;</description></item><item><title>通过 Karabiner-Elements 实现用 Esc 键关闭 Twitter App 的窗口</title><link>http://0x3f.org/posts/using-karabiner-elements-to-close-twitter-app-windows-with-the-esc-key/</link><pubDate>Fri, 25 Aug 2023 16:27:15 +0800</pubDate><guid>http://0x3f.org/posts/using-karabiner-elements-to-close-twitter-app-windows-with-the-esc-key/</guid><description>&lt;p&gt;Twitter for macOS 不支持用 Esc 键关闭图片预览窗口，不符合我的习惯。下面是针对 Twitter App 把 Esc 键映射为 Cmd+W 的配置。&lt;/p&gt;
&lt;script src="https://gist.github.com/xbot/483d360beae96f734f7b44a298e33125.js"&gt;&lt;/script&gt;</description></item><item><title>PictureView: 极简而好用的 macOS 看图 App</title><link>http://0x3f.org/posts/pictureview-simple-easy-to-use-macos-image-viewer-app/</link><pubDate>Fri, 25 Aug 2023 11:01:42 +0800</pubDate><guid>http://0x3f.org/posts/pictureview-simple-easy-to-use-macos-image-viewer-app/</guid><description>&lt;p&gt;之前用的 Xee 看图的时候经常雪花屏，所以换了 &lt;a href="https://wl879.github.io/apps/picview/index.html"&gt;PictureView&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;有这些特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;启动速度很快。&lt;/li&gt;
&lt;li&gt;界面简洁。&lt;/li&gt;
&lt;li&gt;支持关闭图片自动退出。&lt;/li&gt;
&lt;li&gt;提供 4 种浏览布局。&lt;/li&gt;
&lt;li&gt;支持快捷键。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/2023-08-25-11-00-10-pictureview.gif" alt="2023-08-25-11-00-10-pictureview"&gt;&lt;/p&gt;</description></item><item><title>从 macOS 桌面运行 Neovide 的方法</title><link>http://0x3f.org/posts/how-to-run-neovide-from-macos-desktop/</link><pubDate>Mon, 21 Aug 2023 17:07:48 +0800</pubDate><guid>http://0x3f.org/posts/how-to-run-neovide-from-macos-desktop/</guid><description>&lt;p&gt;截至当前版本（0.11.1），Neovide 在 macOS 下只能从命令行启动，为方便起见，有时候我希望通过 RayCast 或者 Dashboard 启动它，或者通过右键菜单“Open with”用它直接打开选中的文件。&lt;/p&gt;
&lt;p&gt;方法是通过 Automator 创建一个“Application”类型的新文档，添加一个“Run AppleScript”的 Action 。然后填入下面的内容：&lt;/p&gt;
&lt;script src="https://gist.github.com/xbot/a2f1d38e8eb02665ef7cf9ba082ccd12.js"&gt;&lt;/script&gt;
&lt;p&gt;最后将文档保存到 Application 目录，命名为“Neovide”。&lt;/p&gt;</description></item><item><title>文石 Poke5S 的使用感受</title><link>http://0x3f.org/posts/hands-on-boox-poke5s/</link><pubDate>Sat, 19 Aug 2023 18:25:50 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-boox-poke5s/</guid><description>&lt;p&gt;之前&lt;a href="http://0x3f.org/posts/hands-on-hanlinyue-read6-pro/"&gt;提到&lt;/a&gt;想挑一个便携美观的微信读书载体，第一眼就被文石 Poke5S 的白色机身吸引了。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230819183323000-a4c6543a66492f2188c1991fb10d56ad.avif" alt="2023-08-19-18-33-23-PXL_20230720_100716361_Original"&gt;&lt;/p&gt;
&lt;p&gt;试用了一段时间，总结了一些比较戳我的优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;便携：可能是长宽最小的 6 寸阅读器。&lt;/li&gt;
&lt;li&gt;美观：白色，做工质感还可以。&lt;/li&gt;
&lt;li&gt;屏幕：Carta 1100 （销售宣传诈称 Carta 1200）。&lt;/li&gt;
&lt;li&gt;操作：日常操作、翻页速度较快。&lt;/li&gt;
&lt;li&gt;配件：支持磁吸保护壳，自动休眠、唤醒。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;屏幕：像素密度 212 PPI 。&lt;/li&gt;
&lt;li&gt;残影：图片显示有明显残影。&lt;/li&gt;
&lt;li&gt;背光：有明显的灯箱效果。&lt;/li&gt;
&lt;li&gt;购买：白色版捆绑销售保护壳，价格太贵。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;鉴于 212 PPI 和背光的灯箱效果降低了阅读体验，考虑到这个价格，最后还是退货了。&lt;/p&gt;</description></item><item><title>翰林阅 Read6 Pro 的使用感受</title><link>http://0x3f.org/posts/hands-on-hanlinyue-read6-pro/</link><pubDate>Sat, 12 Aug 2023 15:29:09 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-hanlinyue-read6-pro/</guid><description>&lt;h6 id="更新"&gt;更新&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;2023-10-02：&lt;a href="http://0x3f.org/posts/hands-on-the-new-hanlinyue-read6-pro/"&gt;重新发售的翰林阅 Read6 Pro 使用体验&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;虽然 Kindle 退出中国对我影响不大，但是近期想看的一些特定版本的书在其它地方没有找到、却在微信读书里垂手可得，所以想着挑个方便的阅读器。先是尝试了文石的 Poke5S ，各方面都挺好，就是屏幕分辨率只有 212 PPI 。然后正好看到了翰林阅 Read6 Pro 预售的消息，看配置非常符合我的想象：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;便携美观：6 英寸、白色。&lt;/li&gt;
&lt;li&gt;显示效果好：Carta 1200、300 PPI、无盖板。&lt;/li&gt;
&lt;li&gt;运行流畅：4G 运存、4核×1.5GHz CPU 。&lt;/li&gt;
&lt;li&gt;微信读书友好：入口在一级菜单。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是到手后很失望。&lt;/p&gt;
&lt;p&gt;最大的问题是背光效果很差，泛蓝、不均匀，看着很难受，到了完全无法接受的程度。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230812153306000-7559c332014655f1df9fe21a0172aae1.avif" alt="2023-08-12-15-33-06-PXL_20230726_093004018"&gt;&lt;/p&gt;
&lt;p&gt;另外前面板边缝很明显，让当年的 Kindle Paperwhite 都自叹不如，按压有咔哒声。第三个问题是字体墨迹不均匀，升级固件后好了点，但还是能看出来。虽然有 4G 运存，但是翻页速度的表现不好。最后就是送了一堆非常差的配件：翻页器做工很差，按键手感难以言表；支架质感极差，有股呛人的味儿；保护套没看，没有开盒的心情了，把印象分直接拉到谷底。&lt;/p&gt;
&lt;p&gt;没想到这都 2023 年了，挑个中意的阅读器还是那么难！&lt;/p&gt;</description></item><item><title>用 SuperDuper! 配合迁移助理加速 Mac 的迁移</title><link>http://0x3f.org/posts/speed-up-mac-migration-with-superduper-and-migration-assistant/</link><pubDate>Sat, 05 Aug 2023 22:29:54 +0800</pubDate><guid>http://0x3f.org/posts/speed-up-mac-migration-with-superduper-and-migration-assistant/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230805224449000-0c1e097634a5155eb47dfab7b380874e.avif" alt="2023-08-05-22-44-49-IMG_0191"&gt;&lt;/p&gt;
&lt;p&gt;用迁移助理迁移数据到一台新的 Mac ，点对点传输提示要几个小时。改用 SuperDuper! 复制到固态移动硬盘，再用迁移助理迁移，几分钟就好了。&lt;/p&gt;
&lt;p&gt;趁着今年 SSD 降价攒了个移动硬盘，把机械的卖了，省了太多时间了。&lt;/p&gt;</description></item><item><title>变形金刚 MPM-13 眩晕玩评</title><link>http://0x3f.org/posts/hands-on-transformer-mpm-13-blackout/</link><pubDate>Sat, 07 Jan 2023 22:20:32 +0800</pubDate><guid>http://0x3f.org/posts/hands-on-transformer-mpm-13-blackout/</guid><description>&lt;p&gt;我对 MPM-13 的感受比较复杂。&lt;/p&gt;
&lt;p&gt;一方面，人形和隐藏形态俱佳，材质和做工在近年官方出品的东西里面也属上乘，变形过程虽然复杂，但是依然有官方玩具常有的逻辑在里面，不像很多第三方的设计为变形而变形。但是同时，面对这较大的体型和复杂的变形步骤，我要做足心理建设才能鼓足勇气变它一次。这不符合我对一款好的变形金刚的判断标准。&lt;/p&gt;
&lt;p&gt;在我看来，变形金刚最大的价值在于变形过程是不是好玩。所谓好玩，就是流畅有逻辑，既不简陋又没有不必要的复杂，像很多第三方为了追求两种形态的极致还原而把变形过程设计得极其复杂就属于舍本逐末了。昨天收拾箱子的时候看到 IDW 的宇宙飞碟、滑翔机等几个指挥官级的老玩具，拿起来随手一变，很有乐趣。回头想想，变形金刚最吸引我们的地方不就在于玩的过程么。讲人形，不如高达，讲隐藏形态，不如各种模型，变形金刚不是什么高大上的东西，相反，就是个闲来无事时拿来享受个人时光和回忆的玩具。&lt;/p&gt;
&lt;p&gt;一款玩具不应该让人有心理负担，所以 MPM-13 是个适合站柜的镇宅神物，但不是个可以随手变个来回享受简单乐趣的好玩具。&lt;/p&gt;
&lt;p&gt;再来聊聊它的本体。&lt;/p&gt;
&lt;p&gt;自从 MP 系列涨价、质量下降以及 3.0 接连翻车之后，最近几年我就没再买过这个系列的东西。这次 MPM-13 实在是挑不出什么大毛病，价格也合适，算是回坑了。&lt;/p&gt;
&lt;p&gt;八角尖尖，不成想盒封最完美的一次来自拼多多。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230107230832000-99d11859dd32c93780cc0db968c2cb28.avif" alt="八角尖尖，不成想盒封最完美的一次来自拼多多"&gt;&lt;/p&gt;
&lt;p&gt;隐藏形态是 MH-53 重型运输直升机，解决了 SS-08 底盘暴露的问题，360 度无死角，即便在 MP 线里也是无出其右。就是缺个支架，飞机没有支架就没有灵魂。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230107230836000-118f0c7b48444ba233f9e199fee79bbc.avif" alt="隐藏形态，MH-53 重型运输直升机"&gt;&lt;/p&gt;
&lt;p&gt;人形，迄今最还原的眩晕。电影线最失败的地方在于反派的造型和人设塑造得太差劲，眩晕在霸天虎里算是相对较好的，人设没那么不堪，反派形态的猥琐特征被大量的板件遮盖，反而显得很有机械感。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230107230840000-6d6fda21c70ab791ad2931f95fc87b33.avif" alt="人形，迄今最还原的眩晕"&gt;&lt;/p&gt;</description></item><item><title>读《叫魂》小记</title><link>http://0x3f.org/posts/a-short-review-of-soulstealers/</link><pubDate>Thu, 22 Dec 2022 22:29:41 +0800</pubDate><guid>http://0x3f.org/posts/a-short-review-of-soulstealers/</guid><description>&lt;p&gt;前段时间大概是因为防疫政策的关系，有几个书名在网上很常见，《叫魂》是其中的一个。&lt;/p&gt;
&lt;p&gt;书的主要内容是乾隆年间起自民间、漫延数省的一阵对妖术索魂的社会性恐慌，并最终被灌水诗人、盖章爱好者乾隆大帝解读为针对满清统治的政治阴谋，继而调动全国官僚系统追索因刑讯逼供而幻想出来的幕后谋主的事件。围绕叫魂事件对其产生的社会背景、皇帝的心理和官僚阶层的应对之策等方面做了一些讨论。&lt;/p&gt;
&lt;p&gt;翻译札记里有段话说得很好：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;君主是如何实现其对官僚的控制的呢？孔飞力通过对叫魂妖术危机的进一步讨论，提出了“政治罪”这样一个概念。他强调了政治罪为帝国政治的运作提供了燃料。按照他的定义，政治罪指的是威胁帝国安全的各种形式的谋反，它们是超出常规的非常事件，无法由官僚制度的行政常规来处理。这种非常的形势给了君主极大的自由来动员、驱策和整肃他的官僚，并强化他对官僚机器的控制（因为在常规情况下，一切行政事务都可以、而且应该照章办事，专制君主也不得不遵守由这些行政则例所定下的游戏规则，这种常规的管理给君主的活动留下的空间有限） 。在叫魂危机中，乾隆皇帝正是利用了妖术恐惧这样的非常事件，迫使整个官僚机器把清剿当做压倒一切的政治，并以清剿的表现来赏罚官僚，从而强化他对官僚的控制的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;太祖的大字报和世宗的轮子大抵如此，但如果非要影射当下以寄托对时情的不满，似乎又有点玩弄阴谋论的肤浅的小聪明了。&lt;/p&gt;</description></item><item><title>OmniFocus 插件 generate-work-journal v4.0 小记</title><link>http://0x3f.org/posts/omnifocus-plugin-generate-work-journal-v2.0-release-notes/</link><pubDate>Sun, 18 Dec 2022 16:32:34 +0800</pubDate><guid>http://0x3f.org/posts/omnifocus-plugin-generate-work-journal-v2.0-release-notes/</guid><description>&lt;p&gt;OmniFocus 是个非常强大的待办列表 App ，最大的特点之一是支持开发插件。如果你跟我一样有各种稀奇古怪的需求且其它待办 App 不能满足时，可以试试它，尽管很贵，但是很值。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/omnifocus-plugin-generate-work-journal"&gt;generate-work-journal&lt;/a&gt; 是一个生成工作日志的工具，可以根据当天完成的、满足特定条件的任务一键生成日报，以节省时间。&lt;/p&gt;
&lt;p&gt;包含以下特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只对特定目录下的日志有效。&lt;/li&gt;
&lt;li&gt;支持大型任务（包含多项任务的 project ）和单项任务。&lt;/li&gt;
&lt;li&gt;多种输出格式：
&lt;ul&gt;
&lt;li&gt;纯文本&lt;/li&gt;
&lt;li&gt;Markdown 无序列表&lt;/li&gt;
&lt;li&gt;Markdown 有序列表&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;自动追加任务状态描述：
&lt;ul&gt;
&lt;li&gt;进行中&lt;/li&gt;
&lt;li&gt;已完成&lt;/li&gt;
&lt;li&gt;自定义&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;通过标签过滤不需要的记录。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今天 generate-work-journal 发布了 4.0 版本，加入了自动判断状态为“进行中”的任务的功能。对于设置为周期重复的任务，如果还存在待执行状态的记录，那么当天已完成的记录将被认为是“进行中”。可以在设置选项中指定该状态的文字描述，和“已完成”状态一样，如果文字描述为空，最终生成的日志内容将不包含状态的描述。&lt;/p&gt;</description></item><item><title>OmniFocus 插件 checklist v2.0 小记</title><link>http://0x3f.org/posts/omnifocus-plugin-checklist-v2.0-release-notes/</link><pubDate>Sun, 11 Dec 2022 18:20:34 +0800</pubDate><guid>http://0x3f.org/posts/omnifocus-plugin-checklist-v2.0-release-notes/</guid><description>&lt;p&gt;OmniFocus 是个非常强大的待办列表 App ，最大的特点之一是支持开发插件。如果你跟我一样有各种稀奇古怪的需求且其它待办 App 不能满足时，可以试试它，尽管很贵，但是很值。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/omnifocus-plugin-checklist"&gt;checklist&lt;/a&gt; 是一个把 OmniFocus 变成检查清单 App 的插件，源自我周期性重复检查一些事项的需求，例如：收拾行李、储备物资和审查代码。&lt;/p&gt;
&lt;p&gt;之前用过一款专门的手机 App ，对于检查清单这个领域来说，确实做得已经很极致了，但是最大的问题是没有电脑端，对于像代码审查这种需要更多、更复杂的编辑操作的清单来说，在手机上操作真是太麻烦了。还有一点就是手机毕竟还不是一个常规意义上的“正经”工具，工作时间捧着手机显得很奇怪。&lt;/p&gt;
&lt;p&gt;checklist 就是这种背景下的产物。它的基本逻辑是：用 OmniFocus 的 project 当清单模板，一个 project 对应一个模板。模板集中存在专门的 folder 下。在需要检查清单的 project 下点击插件按钮选择清单模板，将在该 project 下创建和模板中相同的任务列表。&lt;/p&gt;
&lt;p&gt;以下录屏直观地展示了插件的用法：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/2022-12-11-18-57-32-omnifocus-plugin-checklist-v2-demo.gif" alt="2022-12-11-18-57-32-omnifocus-plugin-checklist-v2-demo"&gt;&lt;/p&gt;
&lt;p&gt;凭借 OmniFocus 原本就很强大的任务列表功能， checklist 近乎完美地实现了我对一个检查清单 App 的需求。不光我的手机上又少了一个 App ，而且考虑到那个 App 高达一百多的售价，说支持多端的 checklist 价值 200￥ 似乎也不过分。&lt;/p&gt;</description></item><item><title>OmniFocus 插件 reschedule-objects v3.0 小记</title><link>http://0x3f.org/posts/omnifocus-plugin-reschedule-objects-v3.0-release-notes/</link><pubDate>Fri, 02 Dec 2022 19:53:34 +0800</pubDate><guid>http://0x3f.org/posts/omnifocus-plugin-reschedule-objects-v3.0-release-notes/</guid><description>&lt;p&gt;OmniFocus 是个非常强大的待办列表 App ，最大的特点之一是支持开发插件。如果你跟我一样有各种稀奇古怪的需求且其它待办 App 不能满足时，可以试试它，尽管很贵，但是很值。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/omnifocus-plugin-reschedule-objects"&gt;reschedule-objects&lt;/a&gt; 是一个给选中的任务或项目快速排期的插件，源自我特定的时间做特定的事的需求。&lt;/p&gt;
&lt;p&gt;今天 reschedule-objects 发布了 3.0 版本，主要包括三部分的变化。&lt;/p&gt;
&lt;p&gt;首先是重构。随着我写的插件数的增加，有些代码可以复用，有些 Omni Automation API 比较烦琐，所以有了封装一个工具类的想法，正好 Omni 应用也支持这样，所以封装了 &lt;a href="https://github.com/xbot/omnifocus-plugin-libdev"&gt;libdev&lt;/a&gt; 开发库。另外，之前很多地方写得很差劲，这次也一并优化了一下。&lt;/p&gt;
&lt;p&gt;其次是用多选组件模拟单选操作，实现了用户体验的提升。Omni Automation API 对于单选操作只提供了下拉列表这一个组件，对于高频操作会显得很低效，这段时间用下来觉得很难受。文档说表单的验证方法可以增减表单里的字段，利用这一点曲线解决了这个问题，用多选组件实现了 radio group 。缺点是切换选项时表单可能产生抖动。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/2022-12-11-16-57-10-omnifocus-plugin-checklist-v3-01.gif" alt="2022-12-11-16-57-10-omnifocus-plugin-checklist-v3-01"&gt;&lt;/p&gt;
&lt;p&gt;第三个变化是加入了清除排期的功能。目前还需要通过同一个入口触发，最多需要三次点击。还有优化空间，考虑未来重构成多 Action 的插件，可以通过单独的按钮触发，最少只要一次点击就可以了。&lt;/p&gt;</description></item><item><title>保存 tweet 到 OmniFocus 的快捷指令</title><link>http://0x3f.org/posts/a-shortcuts-that-saves-tweets-to-omnifocus/</link><pubDate>Tue, 22 Nov 2022 21:34:25 +0800</pubDate><guid>http://0x3f.org/posts/a-shortcuts-that-saves-tweets-to-omnifocus/</guid><description>&lt;p&gt;保存 tweet 到 OnniFocus 并提取内嵌链接的快捷指令，绕过了iOS 16 快捷指令“Make rich text from HTML”丢失编码信息导致乱码的 bug 。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.icloud.com/shortcuts/fc68643daa044b44959f16b0a94ec598"&gt;https://www.icloud.com/shortcuts/fc68643daa044b44959f16b0a94ec598&lt;/a&gt;&lt;/p&gt;</description></item><item><title>用 Obsidian 写博客的方法</title><link>http://0x3f.org/posts/how-to-write-blog-with-obsidian/</link><pubDate>Sun, 23 Oct 2022 17:09:28 +0800</pubDate><guid>http://0x3f.org/posts/how-to-write-blog-with-obsidian/</guid><description>&lt;p&gt;我用 Hugo + GitHub Pages 写博客，之前一直通过命令新建文章，然后在编辑器里一项一项修改 Front Matters ，最后再通过命令提交上去。有一天突然觉得这样太麻烦了，应该可以用图形界面简化一下。&lt;/p&gt;
&lt;p&gt;Typora 收费之后，Obsidian 可能是最好的免费 Markdown 编辑器了。这里用到三个插件：QuickAdd 、 Templater 和 Obsidian Git 。&lt;/p&gt;
&lt;p&gt;在 Hugo 目录下创建两个子目录 &lt;code&gt;templates&lt;/code&gt; 和 &lt;code&gt;scripts&lt;/code&gt; ，设置 Templater 的选项 &lt;code&gt;Template folder location&lt;/code&gt; 为 &lt;code&gt;templates&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;然后在 &lt;code&gt;templates&lt;/code&gt; 目录下创建模板 &lt;code&gt;New Post.md&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;title: &amp;#34;{{VALUE:articleTitle}}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;slug: &amp;#34;{{VALUE:articleSlug}}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;date: {{VALUE:articleTimestamp}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;categories: [&amp;#34;{{VALUE:articleCategory}}&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tags:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;toc: false
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;draft: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;scripts&lt;/code&gt; 下创建脚本 &lt;code&gt;create_new_post.js&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quickAddApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inputPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Blog - Title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quickAddApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inputPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Blog - Slug&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quickAddApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkboxPrompt&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;计算机&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;青梅煮酒&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;行见&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;计算机&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;undefined&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;articleTitle&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;articleSlug&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;articleFilename&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[^A-Za-z0-9\s]/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\s+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;articleCategory&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;articleTimestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quickAddApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;YYYY-MM-DDTHH:mm:ssZ&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;QuickAdd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后在 QuickAdd 里创建一个新的 Macro ，先添加脚本 &lt;code&gt;create_new_post&lt;/code&gt; （位置 1），再创建一个 Template Choice （位置 2）：&lt;/p&gt;</description></item><item><title>自动设置节假日和工作日闹钟的快捷指令</title><link>http://0x3f.org/posts/yet-another-shortcuts-that-sets-alarms-for-chinese-holidays-and-workdays-automatically/</link><pubDate>Thu, 20 Oct 2022 22:23:04 +0800</pubDate><guid>http://0x3f.org/posts/yet-another-shortcuts-that-sets-alarms-for-chinese-holidays-and-workdays-automatically/</guid><description>&lt;p&gt;写了个自动设置节假日和工作日闹钟的快捷指令，数据源用的是苹果官方的“中国大陆节假日”日历。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.icloud.com/shortcuts/97960ed8326e43d387b0d7bb459667dd"&gt;https://www.icloud.com/shortcuts/97960ed8326e43d387b0d7bb459667dd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;需要先订阅上述日历，订阅方法见这个快捷指令里的说明。&lt;/p&gt;
&lt;p&gt;最后把它配置到自动化（比如助眠开始时执行）里就可以了。&lt;/p&gt;</description></item><item><title>用 Hammerspoon 收集 Arc 浏览器网页到 OmniFocus 的方法</title><link>http://0x3f.org/posts/how-to-collect-webpage-from-the-arc-browser-to-omnifocus/</link><pubDate>Wed, 19 Oct 2022 23:02:50 +0800</pubDate><guid>http://0x3f.org/posts/how-to-collect-webpage-from-the-arc-browser-to-omnifocus/</guid><description>&lt;p&gt;我用 &lt;a href="https://www.hammerspoon.org/"&gt;Hammerspoon&lt;/a&gt; 收集网页到 &lt;a href="https://www.omnigroup.com/omnifocus/"&gt;OmniFocus&lt;/a&gt; ，它的 &lt;a href="https://www.hammerspoon.org/Spoons/SendToOmniFocus.html"&gt;SendToOmniFocus&lt;/a&gt; 对 Chrome 家族的浏览器有原生的支持，但并不适用于 &lt;a href="https://thebrowser.company/"&gt;Arc 浏览器&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;看 SendToOmniFocus 的源码是用 Apple Script 获取 Chrome 家族浏览器中网页的信息的，但最初我没有解决怎样用同样的办法拿到 Arc 浏览器网页信息的问题。所以采取通过剪贴板中转的方式实现。&lt;/p&gt;
&lt;p&gt;首先配置 &lt;a href="https://github.com/brookhong/Surfingkeys"&gt;Surfingkeys&lt;/a&gt; 实现把网页信息组装成特定格式复制到剪贴板：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;mapkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yO&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Copy OmniFocus sensible info.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;yankOmniFocusSensibleInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;yankOmniFocusSensibleInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;info_arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;info_arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;#omnifocus_sensible&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;info_arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;info_arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info_arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后在 Hammerspoon 中监听剪贴板，一旦发现特定格式的文本，就调用 Apple Script 填充解析到的网页信息到 OmniFocus 的对话框：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- Interpolate table values into a string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- From http://lua-users.org/wiki/StringInterpolation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="kr"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;interp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;($%b{})&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- Read a whole file into a string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="kr"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;slurp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io.open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;*a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;pasteboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hs.pasteboard&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="kr"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;open_omnifocus_edit_dialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;module_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;debug.getinfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;(.*/)&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;template_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module_dir&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;../templates/add_webpage_to_omnifocus.tpl&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slurp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;as_script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;interp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hs.osascript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applescript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as_script&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;GetOption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;watch_omnifocus_sensible_data&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;off&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;on&amp;#39;&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OmniFocusPasteboardWatcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pasteboard.watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pasteboard_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="kr"&gt;in&lt;/span&gt; &lt;span class="n"&gt;string.gmatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pasteboard_content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[^&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;]+&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;table.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#omnifocus_sensible&amp;#39;&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;open_omnifocus_edit_dialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OmniFocusPasteboardWatcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;后来解决了前面提到的问题，可以直接获取网页信息的 Apple Script 如下：&lt;/p&gt;</description></item><item><title>用 Caddy 做 Home Lab 的反向代理</title><link>http://0x3f.org/posts/reverse-proxying-home-lab-with-caddy/</link><pubDate>Sun, 16 Oct 2022 22:37:08 +0800</pubDate><guid>http://0x3f.org/posts/reverse-proxying-home-lab-with-caddy/</guid><description>&lt;p&gt;我原本用 &lt;a href="https://docs.linuxserver.io/general/swag"&gt;SWAG&lt;/a&gt; 做 Home Lab 的反向代理，它自带很多服务的配置模板，只需要复制后改几个参数就能工作，还有通过 ACME 自动更新 SSL 证书的功能，但是从某个时间起，首次访问经由它代理的服务会报 404 或 502 的错误，刷新页面就恢复正常，然后隔段时间后又会再次发生，另外还会偶尔出现页面无法显示最新的状态的问题，尤以当服务出错时发生居多。&lt;/p&gt;
&lt;p&gt;最近尝试用 &lt;a href="https://caddyserver.com/docs/"&gt;Caddy&lt;/a&gt; 代替 SWAG ，效果非常好，再也没有出现上述问题。而且 Caddy 的使用很简单，只需要在 Caddyfile 中加几行配置信息就能实现对一个服务的反向代理。当然，它也集成了自动更新 SSL 证书的功能。此外，它的镜像只有 80 多 MB ，在我测试的几个反向代理服务里是最节省空间的。&lt;/p&gt;
&lt;p&gt;出于安全考虑，我没有把 Home Lab 的服务暴露在公网上，所以需要通过 DNS challenge 的方式申请 SSL 证书。我的 Docker 容器部署在 Unraid 上，官方软件仓库里的 Caddy 镜像并不包含 Cloudflare 的模块，所以找了个打包了该模块的&lt;a href="https://github.com/SlothCroissant/caddy-cloudflaredns"&gt;镜像&lt;/a&gt;，看起来更新得还很及时。&lt;/p&gt;
&lt;p&gt;镜像的 README 里有申请 Cloudflare API Token 的说明，部署容器前填到环境变量里即可。这里有个小坑，创建容器前需要手动创建 Caddyfile ，空文件就行，否则会报错：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Are you trying to mount a directory onto a file&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Caddy 不如 SWAG 的地方是没有为服务提供配置模板，所以我保留了后者的配置目录，作为在前者中配置服务时的参考。以下是我的 Caddyfile 的示例，展示了怎样配置泛域名的反向代理和 SSL 证书的自动申请，以及服务的几种典型反向代理配置：&lt;/p&gt;</description></item><item><title>Leaderf-phpnamespace: Yet another PHP namespace resolver</title><link>http://0x3f.org/posts/leaderf-phpnamespace-yet-another-php-namespace-resolver/</link><pubDate>Sun, 25 Sep 2022 22:33:13 +0800</pubDate><guid>http://0x3f.org/posts/leaderf-phpnamespace-yet-another-php-namespace-resolver/</guid><description>&lt;p&gt;This plugin uses the power of &lt;a href="https://github.com/Yggdroot/LeaderF"&gt;LeaderF&lt;/a&gt; to perform PHP namespace related tasks.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/Leaderf-phpnamespace"&gt;https://github.com/xbot/Leaderf-phpnamespace&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="features"&gt;Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Insert &lt;code&gt;use&lt;/code&gt; statements for FQCNs.&lt;/li&gt;
&lt;li&gt;Sort &lt;code&gt;use&lt;/code&gt; statements alphabetically.&lt;/li&gt;
&lt;li&gt;Expand class names to FQCNs.&lt;/li&gt;
&lt;li&gt;Insert namespace for the current file.&lt;/li&gt;
&lt;li&gt;All the above features support the fuzzy searching function and all the three modes (nameonly, fullpath and regex) provided by LeaderF.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="requirements"&gt;Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yggdroot/LeaderF"&gt;LeaderF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ctags is properly configured in Vim/Neovim.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;Use any of your favourite plugin manager to install it, for example:&lt;/p&gt;</description></item><item><title>Unraid 6.11 弃用 NerdPack 的解决办法</title><link>http://0x3f.org/posts/how-to-install-packages-after-nerdpack-is-deprecated-in-unraid-6.11/</link><pubDate>Sun, 25 Sep 2022 21:29:41 +0800</pubDate><guid>http://0x3f.org/posts/how-to-install-packages-after-nerdpack-is-deprecated-in-unraid-6.11/</guid><description>&lt;p&gt;Unraid 6.11 的 release note 没提弃用 NerdPack ，浪费了我很多时间。😞&lt;/p&gt;
&lt;p&gt;当前版本的 Unraid 是基于 Slackware 15.0 的，可以手动从以下站点下载软件包手动安装：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://slackware.pkgs.org/15.0/slackware-x86_64/"&gt;https://slackware.pkgs.org/15.0/slackware-x86_64/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slackonly.com/pub/packages/15.0-x86_64/"&gt;https://slackonly.com/pub/packages/15.0-x86_64/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;把下载的软件包放到运行中的 Unraid 的 &lt;code&gt;/boot/extra&lt;/code&gt; 目录（不存在就手动创建）下，重启系统后自动安装或者通过 &lt;code&gt;installpkg&lt;/code&gt; 命令手动安装。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;installpkg vim-8.2.4256-x86_64-1.txz
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;更简单的方法是使用 &lt;a href="https://github.com/ich777/un-get"&gt;un-get&lt;/a&gt; ：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;un-get search vim
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;un-get install python3 python-pip python-setuptools
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;un-get remove vim
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;un-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;un-get cleanup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;un-get upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个命令目前不解决依赖关系，而且存在部分包无法下载或找不到的现象，还是需要手动干预。&lt;/p&gt;
&lt;p&gt;作者没有在项目主页写安装说明，而是写在 &lt;a href="https://www.reddit.com/r/unRAID/comments/wy9nft/unget_a_simple_command_line_tool_to_install/"&gt;Reddit 帖子&lt;/a&gt;里了。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2022-10-07-更新"&gt;2022-10-07 更新&lt;/h3&gt;
&lt;p&gt;出了个新的 NerdTools ，界面和 NerdPack 一样难用，包的数量现在还很少，但版本较新，还有一些 un-get 目前搜不到的包（比如: fzf）。可以作为补充。&lt;/p&gt;</description></item><item><title>用 Neovim 调试 RESTful 接口</title><link>http://0x3f.org/posts/send-restful-requests-with-neovim/</link><pubDate>Sun, 18 Sep 2022 11:31:16 +0800</pubDate><guid>http://0x3f.org/posts/send-restful-requests-with-neovim/</guid><description>&lt;p&gt;纯文本有很多好处，比如可以用 Git 管理，方便备份和追溯，方便多机同步和分享。&lt;/p&gt;
&lt;p&gt;之前使用 VS Code 的插件 Rest Client ，从浏览器后台复制请求数据过来就可以用，很方便。但是存在一些用起来不舒服的地方，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不方便对接口分组管理。&lt;/li&gt;
&lt;li&gt;不方便快速查找接口。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些在对纯文本操作效率更高的 Vim 里都可以解决，但是之前尝试过的一些 Vim 的 RESTful 客户端插件还不成熟，最近发现 &lt;a href="https://github.com/rest-nvim/rest.nvim"&gt;rest.nvim&lt;/a&gt; 基本可以满足日常使用需要了。&lt;/p&gt;
&lt;p&gt;rest.nvim 是个 Neovim 的插件，和 Rest Client 支持的格式差异较小，迁移很方便。这样我就可以用 Vim 的折叠特性对接口分组管理，用插件 Leaderf 的模糊查找特性快速定位接口，当然，对纯文本的任何编辑和操作在 Vim 里就是浑然天成、行云流水的。&lt;/p&gt;
&lt;p&gt;它的大致用法如下：&lt;/p&gt;
&lt;p&gt;在工作目录下创建环境变量文件 &lt;code&gt;.env&lt;/code&gt; ：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://myapp.dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;header_accept_json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;application/json, application/problem+json, text/plain, */*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;header_content_type_json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;application/json;charset=utf-8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;header_cookie_debug_session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;XDEBUG_SESSION=1;app_session=1ObUjvLvEYjVhJ8tbzn5BorN7TViNtI1S625140e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;user_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;user@test.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;user_password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在工作目录下创建请求文件（例如 &lt;code&gt;myapp.http&lt;/code&gt; ）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;### Login
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST {{base_url}}/v1/sessions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Accept: {{header_accept_json}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Content-Type: {{header_content_type_json}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Cookie: {{header_cookie_debug_session}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;{&amp;#34;email&amp;#34;: &amp;#34;{{user_email}}&amp;#34;, &amp;#34;password&amp;#34;: &amp;#34;{{user_password}}&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;### Get an article
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;GET {{base_url}}/v1/articles/DiJeb7IQHo8FOFkXulieyA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Accept: {{header_accept_json}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Cookie: {{header_cookie_debug_session}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;### Create an article
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST {{base_url}}/v1/articles
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Accept: {{header_accept_json}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Cookie: {{header_cookie_debug_session}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Content-Type: {{header_content_type_json}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;title&amp;#34;: &amp;#34;Hello world&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;Content&amp;#34;: &amp;#34;This is a dummy post.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后就可以用插件提供的命令触发请求了。&lt;/p&gt;</description></item><item><title>给 Vim 插件做快照</title><link>http://0x3f.org/posts/create-snapshot-for-vim-plugins/</link><pubDate>Tue, 06 Sep 2022 23:28:26 +0800</pubDate><guid>http://0x3f.org/posts/create-snapshot-for-vim-plugins/</guid><description>&lt;p&gt;我的 Vim 插件数快到 150 了，弊端也越来越明显。&lt;/p&gt;
&lt;p&gt;最大的问题是稳定性，经常批量更新后发现某个功能不工作了，尤其是大部分问题只有在用到的时候才发现，非常影响效率。&lt;/p&gt;
&lt;p&gt;我用的插件管理工具是 &lt;a href="https://github.com/junegunn/vim-plug"&gt;vim-plug&lt;/a&gt; ，虽然有回滚到上一次的功能，但是我手比较欠，经常频繁更新，往往发现一个问题时已经更新了几次了，所以这个功能对我来说不是很适用。&lt;/p&gt;
&lt;p&gt;好在它提供了做快照的命令 &lt;code&gt;:PlugSnapshot&lt;/code&gt; ，其实就是把当前所有插件的 Git 哈希值输出到一个 Vim 脚本里，恢复快照的时候只要执行这个脚本就行了。&lt;/p&gt;
&lt;p&gt;为了方便使用，创建一个自定义命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;SnapshotPlugins&lt;/span&gt; &lt;span class="nx"&gt;PlugSnapshot&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/.vim/&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;.&lt;span class="nx"&gt;lock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后把生成的 &lt;code&gt;plugin.lock&lt;/code&gt; 文件加入 Git 仓库，必要的时候可以利用 &lt;code&gt;git bisect&lt;/code&gt; 快速找到问题出处。&lt;/p&gt;
&lt;p&gt;恢复的命令如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vim -S plugin.lock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Leaderf-folder: Quickly open a subfolder</title><link>http://0x3f.org/posts/the-leaderf-folder-plugin/</link><pubDate>Sun, 07 Aug 2022 17:31:50 +0800</pubDate><guid>http://0x3f.org/posts/the-leaderf-folder-plugin/</guid><description>&lt;p&gt;&lt;a href="https://github.com/xbot/LeaderF-folder"&gt;LeaderF-folder&lt;/a&gt; is a plugin for &lt;a href="https://github.com/Yggdroot/LeaderF"&gt;LeaderF&lt;/a&gt; that aims to open a subfolder quickly.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/LeaderF-folder/main/image/screencast.gif" alt="screen cast"&gt;&lt;/p&gt;
&lt;h2 id="requirements"&gt;Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yggdroot/LeaderF"&gt;LeaderF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sharkdp/fd"&gt;fd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/elihunter173/dirbuf.nvim"&gt;Dirbuf&lt;/a&gt;: Optional, can be changed to other file managers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;p&gt;This plugin takes &lt;a href="https://github.com/elihunter173/dirbuf.nvim"&gt;Dirbuf&lt;/a&gt; as the default solution to open the chosen subfolder. You can use the following option to customize it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;Lf_FolderAcceptSelectionCmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Dirbuf&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="usage"&gt;Usage&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;LeaderfFolder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Press &lt;code&gt;F1&lt;/code&gt; to get more help&lt;/p&gt;</description></item><item><title>Laravel Horizon 简介</title><link>http://0x3f.org/posts/an-introduction-of-laravel-horizon/</link><pubDate>Sat, 06 Aug 2022 20:22:36 +0800</pubDate><guid>http://0x3f.org/posts/an-introduction-of-laravel-horizon/</guid><description>&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;Horizon 针对 Laravel 的 Redis 队列，增加了可视化、进程池等特性。&lt;/p&gt;
&lt;h2 id="特性"&gt;特性&lt;/h2&gt;
&lt;h3 id="可视化仪表板"&gt;可视化仪表板&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20220806202748000-1d93be35f42b67a410c72a2724557806.avif" alt="2022-08-06-20-27-48-xu94E4"&gt;&lt;/p&gt;
&lt;h3 id="worker-进程池的维护和调度"&gt;Worker 进程池的维护和调度&lt;/h3&gt;
&lt;h4 id="词汇表"&gt;词汇表&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;master supervisor: 主进程，通过 &lt;code&gt;proc_open()&lt;/code&gt; 启动 supervisor 子进程。&lt;/li&gt;
&lt;li&gt;environments: 可以按 &lt;code&gt;APP_ENV&lt;/code&gt; 针对不同环境创建多套配置。&lt;/li&gt;
&lt;li&gt;supervisors: Horizon 自己的进程池概念，与托管后台进程的软件 Supervisor 没有关系。&lt;/li&gt;
&lt;li&gt;workers: 队列消费者进程，每个 supervisor 中包含多个 worker。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="负载均衡策略"&gt;负载均衡策略&lt;/h4&gt;
&lt;h5 id="false"&gt;false&lt;/h5&gt;
&lt;p&gt;一个 supervisor 下的所有 worker 全部用于按队列名称的顺序逐个队列消费任务。&lt;/p&gt;
&lt;h5 id="simple"&gt;simple&lt;/h5&gt;
&lt;p&gt;一个 supervisor 下的所有 worker 被平均分配给每个队列。&lt;/p&gt;
&lt;h5 id="auto"&gt;auto&lt;/h5&gt;
&lt;p&gt;一个 supervisor 下空闲的 worker 会被优先分配给负载最高的队列。同时保证空闲队列有配置项 minProcesses 数量的 worker 待命。&lt;/p&gt;
&lt;h3 id="超时提醒"&gt;超时提醒&lt;/h3&gt;
&lt;p&gt;如果一个队列执行任务的时间超过预先配置的时间限制，horizon 将终止该任务并可以通过短信、邮件或 Slack 发送通知。&lt;/p&gt;
&lt;p&gt;Horizon 每分钟查询一次执行任务的时间超过配置值的队列：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20220806203029000-71a9ffdeafce1d7d7ecd3ca08c9e4e47.avif" alt="2022-08-06-20-30-29-t2RJyM"&gt;&lt;/p&gt;
&lt;p&gt;每 5 分钟发送一次通知：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20220806203103000-20932a638ca0fb36721dd2f2ffb6e947.avif" alt="2022-08-06-20-31-03-USbLPG"&gt;&lt;/p&gt;
&lt;h3 id="吞吐量和平均耗时统计"&gt;吞吐量和平均耗时统计&lt;/h3&gt;
&lt;p&gt;需要通过定时任务周期性执行 &lt;code&gt;artisan horizon:snapshot&lt;/code&gt; 命令生成统计数据并存储到 Redis 中。&lt;/p&gt;</description></item><item><title>Pixel 5 每月更新后重刷 Magisk 的步骤</title><link>http://0x3f.org/posts/steps-to-reflash-magisk-after-pixel-5-monthly-update/</link><pubDate>Sat, 25 Jun 2022 17:22:57 +0800</pubDate><guid>http://0x3f.org/posts/steps-to-reflash-magisk-after-pixel-5-monthly-update/</guid><description>&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;下载最新的 &lt;a href="https://developers.google.com/android/images#redfin"&gt;Factory Image&lt;/a&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解压两次得到 boot.img 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用数据线连接电脑并允许 USB 调试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;复制 boot.img 到手机&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;adb push boot.img /sdcard/Download/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在手机上的 Magisk 里给 boot.img 打补丁。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 把打完补丁的文件复制到电脑上&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;adb pull /sdcard/Download/magisk_patched-25101_MNbd5.img .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 启动到 bootloader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;adb reboot bootloader
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 查看设备连接正常&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fastboot devices
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 刷 boot.img&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fastboot flash boot_a magisk_patched-25101_MNbd5.img
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fastboot flash boot_b magisk_patched-25101_MNbd5.img
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 重启&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fastboot reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="参考"&gt;参考&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.droidwin.com/patch-stock-boot-image-flash-magisk/"&gt;How to Patch Stock Boot Image via Magisk and Flash it using Fastboot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.androidinfotech.com/33493-root-google-pixel-5-redfin-android-12/"&gt;Root Google Pixel 5 Android 12 using Magisk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="附更新-pixel-5-的-magisk-缩小状态栏的模块的步骤"&gt;附：更新 Pixel 5 的 Magisk 缩小状态栏的模块的步骤&lt;/h1&gt;
&lt;p&gt;直接覆盖原模块会导致功能不生效。&lt;/p&gt;</description></item><item><title>解决 PHPUnit 生成代码覆盖报告时抛出重复定义类的错误的办法</title><link>http://0x3f.org/posts/the-solution-of-class-redeclaration-error-raised-while-generating-php-code-coverage-report/</link><pubDate>Thu, 23 Jun 2022 14:42:34 +0800</pubDate><guid>http://0x3f.org/posts/the-solution-of-class-redeclaration-error-raised-while-generating-php-code-coverage-report/</guid><description>&lt;p&gt;在生成 Cobertura 格式的代码覆盖报告时程序报了如下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Generating code coverage report in Cobertura XML format &amp;hellip; PHP Fatal error: Cannot declare class App\FakeNamespace\GenericProvider, because the name is already in use in /builds/fake_project/app/FakeNamespace/GenericProvider.php on line 17&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对应的代码和单元测试执行均无问题。&lt;/p&gt;
&lt;p&gt;经排查，直接原因是使用了 Mockery 的 &lt;a href="http://docs.mockery.io/en/latest/reference/instance_mocking.html"&gt;Instance Mocking&lt;/a&gt; &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;特性 mock 代码中的硬依赖关系（&lt;a href="https://robertbasic.com/blog/mocking-hard-dependencies-with-mockery/"&gt;Hard Dependency&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;该特性的实现利用了类的自动加载机制和依赖注入技术。对依赖关系 mock 的实例保存在 Mockery 的容器中，同时生成一个 stub 文件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;Mockery&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mockery_App_FakeNamespace_GenericProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;Container&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// internal code check expectations
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;App\FakeNamespace\GenericProvider::doSomething&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;expectations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当代码中实例化这个类的时候，Mockery 自动加载该文件，从而代替了对原类文件的加载。&lt;/p&gt;</description></item><item><title>ClashX 在使用订阅链接的同时添加自定义规则的方法</title><link>http://0x3f.org/posts/customize-rules-for-clashx-while-using-a-subscribed-link/</link><pubDate>Wed, 22 Jun 2022 22:15:12 +0800</pubDate><guid>http://0x3f.org/posts/customize-rules-for-clashx-while-using-a-subscribed-link/</guid><description>&lt;p&gt;在 ClashX 中使用机场的订阅链接时，如果需要添加自定义的规则，且在定时更新订阅的链接时不会被覆盖，解决的方法是创建一个新的配置文件，使用 Clash 的 &lt;a href="https://github.com/Dreamacro/clash/wiki/configuration#proxy-providers"&gt;proxy-providers&lt;/a&gt; 和 &lt;a href="https://github.com/Dreamacro/clash/wiki/premium-core-features#rule-providers"&gt;rule-providers&lt;/a&gt; 分别引用订阅的链接和开源的规则集：&lt;/p&gt;
&lt;script src="https://gist.github.com/xbot/26f540ae8fad51cf27152f2385caccee.js"&gt;&lt;/script&gt;
&lt;p&gt;然后就可以在 &lt;code&gt;rules&lt;/code&gt; 区块里添加自定义规则了。&lt;/p&gt;</description></item><item><title>使用 lemonade 和 autossh 辅助 Neovim 远程开发</title><link>http://0x3f.org/posts/assisting-neovim-with-remote-development-using-lemonade-and-autossh/</link><pubDate>Thu, 19 May 2022 16:02:34 +0800</pubDate><guid>http://0x3f.org/posts/assisting-neovim-with-remote-development-using-lemonade-and-autossh/</guid><description>&lt;p&gt;我的开发环境部署在 Linux VM 里，普通的远程复制用 &lt;a href="https://github.com/ojroques/vim-oscyank"&gt;vim-oscyank&lt;/a&gt; 插件是可以实现的。但是当我想用 &lt;a href="https://github.com/tpope/vim-fugitive"&gt;fugitive&lt;/a&gt; 的 &lt;code&gt;:GBrowse&lt;/code&gt; 命令打开 Gitlab 链接的时候遇到了困难，甚至我想退而求其次、通过 &lt;code&gt;:GBrowse!&lt;/code&gt; 复制链接都不可得，因为 fugitive 的代码里通过 &lt;code&gt;has('clipboard')&lt;/code&gt; 判断 Vim 是否可以使用系统剪贴板，且我的 Linux VM 不满足该特性的条件（见 &lt;code&gt;:help clipboard&lt;/code&gt;）。所以用 &lt;a href="https://github.com/lemonade-command/lemonade"&gt;lemonade&lt;/a&gt; 解决这个问题。&lt;/p&gt;
&lt;h1 id="实现方式"&gt;实现方式&lt;/h1&gt;
&lt;p&gt;lemonade 虽然支持客户端和服务端直接通信，但是并不提供安全保障，所以我采取 SSH 端口远程转发的方式并用 &lt;a href="https://www.harding.motd.ca/autossh/"&gt;autossh&lt;/a&gt; 保持连接。&lt;/p&gt;
&lt;p&gt;首先分别在服务端（MacOS）和客户端（Linux VM）创建 lemonade 的配置文件（&lt;code&gt;~/.config/lemonade.toml&lt;/code&gt;）：&lt;/p&gt;
&lt;p&gt;服务端：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2489&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;allow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;line-ending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;lf&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;客户端：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2489&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;trans-loopback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;trans-localfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;line-ending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;lf&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后创建 MacOS 的服务配置文件：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~/Library/LaunchAgents/org.0x3f.lemonade.plist&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34; &amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;plist&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;KeepAlive&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;org.0x3f.lemonade&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/donie/.go/bin/lemonade&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;server&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardErrorPath&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/opt/homebrew/var/log/lemonade-error.log&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardOutPath&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/opt/homebrew/var/log/lemonade-output.log&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;WorkingDirectory&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/donie&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;~/Library/LaunchAgents/org.0x3f.autossh.plist&lt;/code&gt;&lt;/p&gt;</description></item><item><title>让 AdGuard Home 和 OpenClash 协同工作</title><link>http://0x3f.org/posts/make-adguard-home-and-openclash-work-together/</link><pubDate>Sun, 06 Mar 2022 12:12:10 +0800</pubDate><guid>http://0x3f.org/posts/make-adguard-home-and-openclash-work-together/</guid><description>&lt;h1 id="家庭网络环境"&gt;家庭网络环境&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;使用 OpenWrt （&lt;em&gt;以下简称 OP&lt;/em&gt; ）做旁路网关&lt;/li&gt;
&lt;li&gt;OP 内建 OpenClash （&lt;em&gt;以下简称 OC&lt;/em&gt; ）访问不存在的网站&lt;/li&gt;
&lt;li&gt;OP 内建 WireGuard （&lt;em&gt;以下简称 WG&lt;/em&gt; ）做内网穿透&lt;/li&gt;
&lt;li&gt;使用 AdGuard Home （&lt;em&gt;以下简称 AH&lt;/em&gt; ）做内网 DNS 和广告过滤&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="之前遇到的问题"&gt;之前遇到的问题&lt;/h1&gt;
&lt;p&gt;不管怎样配置，内网和 WG 下的内网主机名解析和科学上网这 4 种场景总有至少一个不工作。&lt;/p&gt;
&lt;p&gt;期间创建过一个虚拟机做独立的 WG Server ，内建 SmartDNS （&lt;em&gt;以下简称 SD&lt;/em&gt; ）做 AH 的上游，其它场景工作得很好，只是无法通过旁路网关访问不存在的网站。&lt;/p&gt;
&lt;h1 id="解决方法"&gt;解决方法&lt;/h1&gt;
&lt;p&gt;首先如果要正常使用 OC ，就必须使用它的 DNS 解析。&lt;/p&gt;
&lt;p&gt;同时，又要达到使用 AH 做内网主机名解析和广告过滤的目的，所以要把 OC 设成 AH 的唯一上游。&lt;/p&gt;
&lt;p&gt;然后最棘手的问题来了。如果把 AH 设成 dnsmasq 的上游， WG 下不能解析内网主机名。如果把 AH 设成监听 53 端口，则内网无法解析主机名。&lt;/p&gt;
&lt;p&gt;想到之前在独立的 WG Server 上用 SD 在两种场景下都可以正常解析，就试着用它代替 dnsmasq ，结果柳暗花明，所以场景都跑通了。&lt;/p&gt;</description></item><item><title>为 Seafile 配置反向代理的问题</title><link>http://0x3f.org/posts/setup-reverse-proxy-for-seafile/</link><pubDate>Mon, 10 Jan 2022 23:27:08 +0800</pubDate><guid>http://0x3f.org/posts/setup-reverse-proxy-for-seafile/</guid><description>&lt;p&gt;我目前用 SWAG 做 Homelab 的反向代理，在和其它服务一样为 Seafile 配置好后，访问时却报如下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Contradictory scheme headers&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原因是 Seafile 的 Docker 镜像里已经使用了 NGINX 做反代，而且配置里包含和 SWAG 反代相同的配置项：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-NGINX" data-lang="NGINX"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;此时，通过 HTTPS 访问的 SWAG 反代传递的 HEADER 里 &lt;code&gt;X-Forwarded-Proto&lt;/code&gt; 是 &lt;code&gt;https&lt;/code&gt; ，而通过 HTTP 访问的 Seafile 传递的是 &lt;code&gt;http&lt;/code&gt; ，就会报以上错误。&lt;/p&gt;
&lt;p&gt;一种解决方法是，把 Seafile 的 &lt;code&gt;/etc/nginx/conf.d/seafile.nginx.conf&lt;/code&gt; 复制到宿主机，把文件中 &lt;code&gt;X-Forwarded-Proto&lt;/code&gt; 这一行注释掉，然后映射到 Docker 容器的上述路径上：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-v &lt;span class="s1"&gt;&amp;#39;/mnt/user/appdata/seafile/seafile.nginx.conf&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;/etc/nginx/conf.d/seafile.nginx.conf&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;ro&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;需要注意的是，不同版本的 Seafile 镜像里该文件的路径可能不同。&lt;/p&gt;</description></item><item><title>希捷 Basic 简系列和东芝新小黑 A3 的简单对比</title><link>http://0x3f.org/posts/seagate-basic-vs-toshiba-a3/</link><pubDate>Mon, 10 Jan 2022 22:15:16 +0800</pubDate><guid>http://0x3f.org/posts/seagate-basic-vs-toshiba-a3/</guid><description>&lt;p&gt;&lt;a href="http://0x3f.org/posts/my-first-nas/"&gt;把个人数据收集到 NAS&lt;/a&gt; 之后，我开始着手实现 NAS 的异地备份，以补足数据安全的最后一环。&lt;/p&gt;
&lt;p&gt;综合考虑过多种方案之后，感觉还是通过移动硬盘冷备最合适我目前的状况。之前闲置的 Buffalo 3.5&amp;rsquo; 外置硬盘不方便携带，所以放在家里做冗余备份。新买一块 2.5&amp;rsquo; 移动硬盘，每隔一段时间拿回家更新一下备份。&lt;/p&gt;
&lt;p&gt;正好希捷 Basic 简系列和东芝新小黑 A3 有优惠，分别以 380 ￥和 370 ￥的价格入手了 2T 容量款，对比结果如下：&lt;/p&gt;
&lt;p&gt;写入速度方面，200G 大文件，东芝比希捷快大概一分钟，速度分别为 142 MB/s 和 137 MB/s 。另对一个总大小为 140G 的目录（内含多个大文件）做写入的结果也是前者比后者稍快一点。&lt;/p&gt;
&lt;p&gt;温度表现上，写入过程中东芝保持在 41℃ 左右，希捷在 45℃ ~ 51℃ 的范围。&lt;/p&gt;
&lt;p&gt;希捷的尺寸（117mm × 80mm × 14.8mm）比东芝（109mm × 78mm × 14.0mm）明显大一些。&lt;/p&gt;
&lt;p&gt;价格也是东芝更便宜。&lt;/p&gt;
&lt;p&gt;外观上都是塑料感很强，正面简单到只有一个 LOGO ，背面是规格标签，东芝的标签居中而且尤其大，十分难看。正面棱角稍方，底部稍圆润，虽然是为了优化握持感，但我觉得不太好看。希捷只有灰色款有优惠，到手观感确实不如黑色。&lt;/p&gt;
&lt;p&gt;整体来说，东芝的这款 2T 的新小黑 A3 在可见的各方面都比同容量希捷 Basic 简系列更有优势。&lt;/p&gt;</description></item><item><title>我在用的 OmniFocus 插件</title><link>http://0x3f.org/posts/the-omnifocus-plugins-i-am-using/</link><pubDate>Sat, 25 Dec 2021 22:05:40 +0800</pubDate><guid>http://0x3f.org/posts/the-omnifocus-plugins-i-am-using/</guid><description>&lt;h1 id="检查列表"&gt;检查列表&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/omnifocus-plugin-checklist"&gt;xbot/omnifocus-plugin-checklist&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在 OmniFocus 中指定一个 folder ，其下的所有 project 都将作为 checklist 的模板。&lt;/p&gt;
&lt;p&gt;选中一或多个 projects 并触发这个插件的 action ，在弹出的对话框中选择要用的模板，将会在目标 projects 中创建同名 task ，模板中的 tasks 创建为该 task 的子任务。&lt;/p&gt;
&lt;p&gt;模板的 Parallel 、 Complete with last action 、 tags 和 note 会被同步过去。&lt;/p&gt;
&lt;h1 id="生成工作日志"&gt;生成工作日志&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/omnifocus-plugin-generate-work-journal"&gt;xbot/omnifocus-plugin-generate-work-journal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;用于每天下班前一键生成工作日志。&lt;/p&gt;
&lt;p&gt;插件会收集名为 &lt;code&gt;Work&lt;/code&gt; 的目录下当天完成的 Tasks 并根据 Task 标题和 Note 的内容追加不同的状态描述。例如，标题包含“面试”的 Task 不追加状态描述；Note 为空的 Task 追加“完成”，否则追加 Note 的内容。目录目前是写死的，没有做通用性适配。&lt;/p&gt;
&lt;h1 id="打开-jira-ticket"&gt;打开 Jira Ticket&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/omnifocus-plugin-open-jira-ticket"&gt;xbot/omnifocus-plugin-open-jira-ticket&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;从被选中的 Project 标题中解析 Jira Ticket 序号，并根据配置的 Jira URL 打开对应的 Ticket 。如果选中的是 Task ，使用其所属的 Project 。&lt;/p&gt;</description></item><item><title>在 gv.vim 中使用 Diffview.nvim 查看提交内容</title><link>http://0x3f.org/posts/check-commit-with-diffview-in-gv-vim/</link><pubDate>Thu, 23 Dec 2021 14:42:03 +0800</pubDate><guid>http://0x3f.org/posts/check-commit-with-diffview-in-gv-vim/</guid><description>&lt;p&gt;Vim 没有很好的 Git commits viewer ，普通的 diff 模式对于很小的 commit 还行，文件较多、改动较大的 commit 看起来很糟糕。&lt;/p&gt;
&lt;p&gt;gv.vim + Diffview.nvim 是我目前找到的最好的解决方案，下面稍加配置，实现在 gv.vim 的 log 界面通过快捷键 &lt;code&gt;vv&lt;/code&gt; 在 Diffview.nvim 里打开光标所在行对应的 commit ：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;lua&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;_G&lt;/span&gt;.&lt;span class="nx"&gt;diff_view_commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commit_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;diffview&amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commit_hash&lt;/span&gt; .. &lt;span class="s1"&gt;&amp;#39;~1..&amp;#39;&lt;/span&gt; .. &lt;span class="nx"&gt;commit_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;GV&lt;/span&gt; &lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="nx"&gt;vv&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Esc&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;:&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SID&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;DiffviewCommitUnderCursor&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;DiffviewCommitUnderCursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; ^&lt;span class="m"&gt;2&lt;/span&gt;f &lt;span class="nx"&gt;w&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;:&lt;span class="nx"&gt;lua&lt;/span&gt;.&lt;span class="nx"&gt;diff_view_commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;cword&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Hammerspoon 快速入门</title><link>http://0x3f.org/posts/hammerspoon-quick-start/</link><pubDate>Mon, 13 Dec 2021 00:38:06 +0800</pubDate><guid>http://0x3f.org/posts/hammerspoon-quick-start/</guid><description>&lt;p&gt;Hammerspoon（&lt;em&gt;以下简称 HS&lt;/em&gt;）是个很好用的效率工具脚手架，我一直用它实现 APP 启动器、窗口控制、桌面常亮等功能。&lt;/p&gt;
&lt;p&gt;HS 可以通过写脚本可以实现很多个性化的需求。最快的上手方式是直接安装别人写好的&lt;a href="https://github.com/sugood/hammerspoon"&gt;脚本&lt;/a&gt;，然后根据自己的需要稍加修改即可。如果需要深度定制，可以自行实现新的模块。&lt;/p&gt;
&lt;p&gt;HS 使用 Lua 语言。我在 08 年左右用过一年的 &lt;a href="https://www.scintilla.org/SciTE.html"&gt;SciTE&lt;/a&gt; 编辑器，它也通过内嵌的 Lua 配置和扩展功能，所以学了这个语言。当时 NGINX 也才刚起步， Lua 主要还是被用在游戏脚本的开发，并没有现在使用得如此广泛。当时对这个语言的印象是两个极端，一是速度非常快，远远超过 PHP 和 Python ，比 C 也只慢一点点；二是开发库非常简陋，其它脚本语言一行就能实现的常见功能，它往往要从头开始写。&lt;/p&gt;
&lt;p&gt;总之 Lua 是个很精简的语言，可以通过 &lt;a href="https://learnxinyminutes.com/docs/zh-cn/lua-cn/"&gt;Y 分钟速成 X&lt;/a&gt; 的教程快速熟悉它的语法，然后浏览一遍&lt;a href="https://www.hammerspoon.org/go/"&gt;官方入门指南&lt;/a&gt;。HS 提供了很多方便的模块，通过 &lt;a href="https://www.hammerspoon.org/docs/index.html"&gt;API 文档&lt;/a&gt;查看。&lt;/p&gt;
&lt;p&gt;由于经常需要切换键盘映射方案，所以我写了一个简单的模块来实现这个功能：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;hotkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;hs.hotkey&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;hotkey.bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hyper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;K&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;configFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os.getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;HOME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/.config/karabiner/karabiner.json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hs.json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hs.alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Failed to read config file!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;configs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hs.json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;profiles&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;selected&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;switchToIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;switchToIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;switchToIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;switchToIndex&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;selected&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;selected&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hs.json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hs.alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;switchToIndex&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; activated!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;源码见&lt;a href="https://github.com/xbot/hammerspoon/blob/master/modules/karabiner.lua"&gt;这里&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>自动追剧的工作流</title><link>http://0x3f.org/posts/auto-workflow-of-following-tv-series-and-movies/</link><pubDate>Sun, 21 Nov 2021 17:16:15 +0800</pubDate><guid>http://0x3f.org/posts/auto-workflow-of-following-tv-series-and-movies/</guid><description>&lt;p&gt;在 NAS 上搭了个自动追剧、追影的工作流，体验非常好。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/2021-11-21-17-24-06-%E8%87%AA%E5%8A%A8%E8%BF%BD%E5%89%A7%E6%B5%81%E7%A8%8B.svg" alt="自动追剧流程"&gt;&lt;/p&gt;
&lt;p&gt;只需要把想看的美剧或者电影添加到监控列表里，就可以在资源出现之后自动下载并通知到手机或电脑，全程无值守，回家打开电视就能看。&lt;/p&gt;
&lt;p&gt;用到这些工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;del&gt;&lt;strong&gt;Jackett&lt;/strong&gt;: BT 索引工具，负责搜索资源。&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prowlarr&lt;/strong&gt;: Jackett 的平替，和 Radarr/Sonarr 同步 indexer 更方便，对 torrent 网站的限流机制处理得更好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sonarr&lt;/strong&gt;: 电视剧管理工具，负责管理追剧列表、调用 Jackett 搜索、资源监控、下载调度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Radarr&lt;/strong&gt;: 电影管理工具，功能同 Sonarr 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;qBittorrent&lt;/strong&gt;: BT 下载工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChineseSubFinder&lt;/strong&gt;: 字幕搜索工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jellyfin&lt;/strong&gt;: 媒体中心，负责影视剧转码、播放、管理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Telegram&lt;/strong&gt;: 接收通知。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nzb360&lt;/strong&gt;: Android APP ， Sonarr 、 Radarr 、 qBittorrent 的客户端。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LunaSea&lt;/strong&gt;: iOS 的 nzb360 平替，功能和用户体验稍逊后者。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jackett 是 BT 资源索引工具，可以对添加到索引列表中的 BT 资源站点做集中搜索。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20211121175031000-cc4a8baea87ccf303b9b558bc0cb1818.avif" alt="2021-11-21-17-50-31-jackett-01"&gt;&lt;/p&gt;
&lt;p&gt;在 Jackett 因某个 indexer 由于其网站的限流措施而响应失败导致 Radarr 无法搜索且无法修改 indexer 配置后，我改用了 Prowlarr 。它不仅解决了之前遇到的问题，还可以自动同步 indexer 配置到 Radarr 和 Sonarr，并且它们的 UI 也十分统一。&lt;/p&gt;</description></item><item><title>我的第一台 NAS</title><link>http://0x3f.org/posts/my-first-nas/</link><pubDate>Sun, 10 Oct 2021 21:50:12 +0800</pubDate><guid>http://0x3f.org/posts/my-first-nas/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20211109005746000-aeed27aa3f1331dc2b49f4e4e1aef6ff.avif" alt="2021-11-09-00-57-46-my-first-nas"&gt;&lt;/p&gt;
&lt;p&gt;年初终于攒了一台 NAS 。&lt;/p&gt;
&lt;p&gt;之前用一块 1T 的 Buffalo 外置硬盘，但是多年之后，我开始担心这头老水牛还能活多久，况且它的剩余空间也已经不多了。与此同时，手机和电脑的存储空间也像油腻大叔的头发一样越来越少，我必须把沉淀的冷数据迁移出去。身边像有一群饥饿的东西拼命向我伸手。&lt;/p&gt;
&lt;p&gt;而且，随着数码设备的增加，尤其在添了一台 Apple TV 后，出于看 YouTube 的目的，我更需要通过软路由的方式改善家庭网络的翻墙体验。&lt;/p&gt;
&lt;p&gt;再者，以前看影剧都是把 U 盘插到电视或者微投上，或者通过电脑串流，多少也有点麻烦。&lt;/p&gt;
&lt;p&gt;于是打算用一台 All-in-one 解决所有问题。&lt;/p&gt;
&lt;h2 id="硬件规格"&gt;硬件规格&lt;/h2&gt;
&lt;p&gt;最初考虑过群晖、威联通之类的品牌 NAS ，如果能得到更好的使用体验，多花点钱也是可以的。但是看过硬件规格后，感觉我要是以这个价格买了，那就算人生的污点了。&lt;/p&gt;
&lt;p&gt;所以开始准备攒机，按优先级列举一下要求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;美观，不要傻大黑粗的直男风。&lt;/li&gt;
&lt;li&gt;体积小。&lt;/li&gt;
&lt;li&gt;兼顾功耗和性能。&lt;/li&gt;
&lt;li&gt;内存大（16 ~ 32 G）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;先后拟了 4 套配置，和某淘宝店的套装做了一下对比：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center"&gt;-&lt;/th&gt;
&lt;th&gt;淘宝店方案&lt;/th&gt;
&lt;th&gt;价格&lt;/th&gt;
&lt;th&gt;方案 1&lt;/th&gt;
&lt;th&gt;价格&lt;/th&gt;
&lt;th&gt;方案 2&lt;/th&gt;
&lt;th&gt;价格&lt;/th&gt;
&lt;th&gt;方案 3&lt;/th&gt;
&lt;th&gt;价格&lt;/th&gt;
&lt;th&gt;方案 4&lt;/th&gt;
&lt;th&gt;价格&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;机箱&lt;/td&gt;
&lt;td&gt;万由 410&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;万由 410&lt;/td&gt;
&lt;td&gt;680&lt;/td&gt;
&lt;td&gt;迎广 MS04&lt;/td&gt;
&lt;td&gt;930&lt;/td&gt;
&lt;td&gt;蜗牛星际B涂装改风扇&lt;/td&gt;
&lt;td&gt;275&lt;/td&gt;
&lt;td&gt;蜗牛星际B涂装改风扇&lt;/td&gt;
&lt;td&gt;275&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;电源&lt;/td&gt;
&lt;td&gt;益衡 200W&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;益衡 7025B&lt;/td&gt;
&lt;td&gt;236&lt;/td&gt;
&lt;td&gt;机箱内置&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;益衡 7025B&lt;/td&gt;
&lt;td&gt;236&lt;/td&gt;
&lt;td&gt;益衡 7025B&lt;/td&gt;
&lt;td&gt;236&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;主板&lt;/td&gt;
&lt;td&gt;B365-ITX 定制工控板&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;华擎 Z390M-ITX/ac&lt;/td&gt;
&lt;td&gt;1199&lt;/td&gt;
&lt;td&gt;华擎 Z390M-ITX/ac&lt;/td&gt;
&lt;td&gt;1199&lt;/td&gt;
&lt;td&gt;华擎 Z390M-ITX/ac&lt;/td&gt;
&lt;td&gt;1199&lt;/td&gt;
&lt;td&gt;华擎 Z390M-ITX/ac（二）&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;CPU&lt;/td&gt;
&lt;td&gt;I5-8600T&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;I5-8600T&lt;/td&gt;
&lt;td&gt;825&lt;/td&gt;
&lt;td&gt;I5-8600T&lt;/td&gt;
&lt;td&gt;825&lt;/td&gt;
&lt;td&gt;I5-8600T&lt;/td&gt;
&lt;td&gt;825&lt;/td&gt;
&lt;td&gt;I5-8600T&lt;/td&gt;
&lt;td&gt;825&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;散热器&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;AVC 28mm 115X&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;AVC 28mm 115X&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;AVC 28mm 115X&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;AVC 28mm 115X&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;内存&lt;/td&gt;
&lt;td&gt;镁光 DDR4 16G 2666&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;光威 DDR4 2666 16G&lt;/td&gt;
&lt;td&gt;379&lt;/td&gt;
&lt;td&gt;光威 DDR4 2666 16G&lt;/td&gt;
&lt;td&gt;379&lt;/td&gt;
&lt;td&gt;光威 DDR4 2666 16G&lt;/td&gt;
&lt;td&gt;379&lt;/td&gt;
&lt;td&gt;海盗船 DDR4 3000 16G×2（二）&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;总计&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;2999&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;3342&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;3356&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;2937&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;2759&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;最后选了第 4 种。&lt;/p&gt;</description></item><item><title>用微力同步换掉了 Dropbox</title><link>http://0x3f.org/posts/replace-dropbox-with-verysync/</link><pubDate>Wed, 06 Oct 2021 01:24:41 +0800</pubDate><guid>http://0x3f.org/posts/replace-dropbox-with-verysync/</guid><description>&lt;p&gt;我希望找到一种体验较好的方式，把两部手机和索尼黑卡上的照片集中同步到 NAS 上交由 PhotoPrism 托管。&lt;/p&gt;
&lt;p&gt;需求如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可以方便地发送多平台照片到 NAS 。&lt;/li&gt;
&lt;li&gt;可以单向同步手机到 NAS 并忽略手机的删除操作，以节省手机的存储空间。&lt;/li&gt;
&lt;li&gt;可以实现内网穿透且简单稳定。&lt;/li&gt;
&lt;li&gt;便宜。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对比了 PhotoSync 、 Resilio Sync 、 Syncthing 和微力同步（verysync）。&lt;/p&gt;
&lt;p&gt;PhotoSync 作为专门针对同步照片的场景设计的 APP ，完美覆盖前两点，第三点可以借助 NAS 已经配置好的内网穿透实现，但是需要购买相应的 Plan ，而且 Android 和 iOS 平台要各自单独购买。&lt;/p&gt;
&lt;p&gt;Resilio Sync 实现内网穿透需要引入新的依赖关系，不完全满足第三点。&lt;/p&gt;
&lt;p&gt;Syncthing 看起来不错，但是没有官方的 iOS 客户端。&lt;/p&gt;
&lt;p&gt;微力同步据说是基于 Syncthing 的，且补上了后者缺失的一环。各平台免费，只有 iOS 上需要花 12￥ 买 APP 。&lt;/p&gt;
&lt;p&gt;我的 NAS 运行的是 Unraid ， Community Applications 里没有微力同步，在&lt;a href="https://github.com/shuosiw/unraid"&gt;这里&lt;/a&gt;找到了别人配置好的模板，部署很方便。&lt;/p&gt;
&lt;p&gt;试用后因为太好用，干脆把 Dropbox 目录也放到微力同步里，卸载了会占用很多内存且免费方案 3 个端的限制早已捉襟见肘的 Dropbox 。&lt;/p&gt;</description></item><item><title>使用 Remote Torrent Adder 做 qBittorrent 的客户端</title><link>http://0x3f.org/posts/take-remote-torrent-adder-as-client-of-qbittorrent/</link><pubDate>Fri, 20 Aug 2021 00:03:28 +0800</pubDate><guid>http://0x3f.org/posts/take-remote-torrent-adder-as-client-of-qbittorrent/</guid><description>&lt;p&gt;我使用部署在 NAS 中的 qBittorrent 下载资源，每次手动复制磁力链链接到 qBittorrent 的 WebUI 很麻烦。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/remote-torrent-adder/oabphaconndgibllomdcjbfdghcmenci?hl=zh-CN"&gt;Remote Torrent Adder&lt;/a&gt; 是 Chrome 的扩展，可以通过右键菜单把 magnet 等协议的链接发送到多种下载工具，其中就包括 qBittorrent 。&lt;/p&gt;
&lt;p&gt;安装过程不是那么顺利，这个开源小工具并没有对用户体验做更多的优化。&lt;/p&gt;
&lt;p&gt;首先初次安装后，配置界面会有一个初始的、针对 Vuze SwingUI 的配置，需要把它删掉，再添加针对 qBittorrent v4.1+ WebUI 的配置，填好各项配置后选中 &lt;strong&gt;Label/Directory
interactivity&lt;/strong&gt; 复选框。因为我把电影和剧集分目录存放，开始下载前需要指定存储目录。&lt;/p&gt;
&lt;p&gt;第一次点菜单的时候没有反应，后来刷新页面后就好了。但是弹出来的指定下载目录的对话框没有选项，经测试发现第一次需要手工填写，之后有了缓存就可以选了。&lt;/p&gt;</description></item><item><title>用 zsh-autoenv 实现目录级别的 zshrc</title><link>http://0x3f.org/posts/implement-directory-specific-zshrc-with-zsh-autoenv/</link><pubDate>Thu, 19 Aug 2021 23:34:25 +0800</pubDate><guid>http://0x3f.org/posts/implement-directory-specific-zshrc-with-zsh-autoenv/</guid><description>&lt;p&gt;&lt;a href="https://github.com/Tarrasch/zsh-autoenv"&gt;zsh-autoenv&lt;/a&gt; 可以实现当进入特定的目录时加载特定的 zshrc 文件，并当切换到其它目录时取消其中的变更。后者在当前的版本下，对环境变量、命令别名和函数有效。&lt;/p&gt;
&lt;p&gt;使用方法为：&lt;/p&gt;
&lt;p&gt;在目录（如 &lt;code&gt;~/project&lt;/code&gt; ）下创建文件 &lt;code&gt;.autoenv.zsh&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-zsh" data-lang="zsh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;autostash &lt;span class="nv"&gt;TEST_VAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;This is a test variable.&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;autostash &lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;test_cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;echo &amp;#34;This is a test alias.&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;autostash test_func
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;test_func&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;This is a test function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;出于安全考虑， zsh-autoenv 会对 &lt;code&gt;.autoenv.zsh&lt;/code&gt; 做哈希校验，所以第一次或者做变动后进入该目录时，都会要求确认是否接受此文件最新的内容。&lt;/p&gt;
&lt;p&gt;此外，如果进入的目录不存在 &lt;code&gt;.autoenv.zsh&lt;/code&gt;， zsh-autoenv 会自动向上查找最近的同名文件并加载，上溯的层级可以通过配置项定义。&lt;/p&gt;
&lt;p&gt;最后，它提供了一个命令 &lt;code&gt;autoenv-edit&lt;/code&gt; 用来快速打开和编辑 &lt;code&gt;.autoenv.zsh&lt;/code&gt; 文件。&lt;/p&gt;</description></item><item><title>PHPUnit 9.x 性能分析的方法</title><link>http://0x3f.org/posts/method-for-phpunit-9.x-performance-analysis/</link><pubDate>Tue, 17 Aug 2021 14:48:12 +0800</pubDate><guid>http://0x3f.org/posts/method-for-phpunit-9.x-performance-analysis/</guid><description>&lt;p&gt;利用 PHPUnit 9.x 的 extension 特性，可以记录每个测试用例的耗时并存储到 CSV 文件中。&lt;/p&gt;
&lt;p&gt;Extension 代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;Tests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;PHPUnit\Runner\AfterTestHook&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LongRunningTestsLogger&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;AfterTestHook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$log_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;executeAfterTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;log_file&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.csv&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;fputcsv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$time&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;phpunit.xml 的配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;extensions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;extension&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Tests\LongRunningTestsLogger&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;arguments&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;profiling&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/arguments&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/extension&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Archlinux 下 PHP 不能读取 /tmp 下文件的问题</title><link>http://0x3f.org/posts/php-failed-to-open-stream-under-tmp-in-archlinux/</link><pubDate>Mon, 09 Aug 2021 15:27:58 +0800</pubDate><guid>http://0x3f.org/posts/php-failed-to-open-stream-under-tmp-in-archlinux/</guid><description>&lt;p&gt;问题的场景是，以 http 用户运行的 FPM 进程访问 &lt;code&gt;/tmp&lt;/code&gt; 下由普通用户运行的 CLI 进程创建的文件时，报如下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Failed to open stream.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原因是 PHP-FPM 的 systemd 配置中默认对 FPM 进程单独挂载 &lt;code&gt;/tmp&lt;/code&gt; 目录。&lt;/p&gt;
&lt;p&gt;具体对应：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/usr/lib/systemd/system/php-fpm.service&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;中的：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PrivateTmp=true&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Archlinux 下在 /var/run 下创建目录的方法</title><link>http://0x3f.org/posts/create-directory-under-/var/run-in-archlinux/</link><pubDate>Sun, 08 Aug 2021 23:30:18 +0800</pubDate><guid>http://0x3f.org/posts/create-directory-under-/var/run-in-archlinux/</guid><description>&lt;p&gt;Archlinux 使用 &lt;a href="https://wiki.archlinux.org/title/systemd#systemd-tmpfiles_-_temporary_files"&gt;systemd-tmpfiles&lt;/a&gt; 管理 &lt;code&gt;/var/run&lt;/code&gt; 下的临时目录。这意味着如果我手动创建 &lt;code&gt;/var/run/php&lt;/code&gt; 目录，在系统重启后将不复存在。&lt;/p&gt;
&lt;p&gt;解决的办法是修改 &lt;code&gt;/usr/lib/tmpfiles.d/php-fpm.conf&lt;/code&gt; 文件，把默认的目录名 &lt;code&gt;php-fpm&lt;/code&gt; 改成 &lt;code&gt;php&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;但这会带来另一个问题，当 PHP 被重装或升级后，该文件会被覆盖。所以，解决的方法是复制后再修改。&lt;/p&gt;</description></item><item><title>给 Bose QC35 更换新耳罩</title><link>http://0x3f.org/posts/change-muffs-for-bose-qc35/</link><pubDate>Sun, 04 Oct 2020 18:43:16 +0800</pubDate><guid>http://0x3f.org/posts/change-muffs-for-bose-qc35/</guid><description>&lt;p&gt;尽管我用东西很爱惜，QC35 的耳罩表面在前年也开始了剥落，并终于在今年早些时候裂开了。&lt;/p&gt;
&lt;p&gt;了解到官方耳罩太贵（380￥左右），而且就这四年的使用情况而言，质量一般。所以打算买第三方的自己换。最终在淘宝上买了排序靠前、35包邮的蛋白皮款。&lt;/p&gt;
&lt;p&gt;安装过程比较简单（&lt;a href="https://www.bose.cn/zh_cn/support/article/ear-cushion-replacement-qc25.html"&gt;官方说明&lt;/a&gt;），把旧耳罩扯下来，再把新的耳罩的包边逐个塞到耳机的卡扣里就行，就是容易边塞边松脱。&lt;/p&gt;
&lt;p&gt;替换前后：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20201004185953000-3625288134e04b6ae2c366ae1d4eb60b.avif" alt="IMG_7891"&gt;&lt;/p&gt;
&lt;p&gt;用了两天，不管是外观还是材质，和原装没有区别。&lt;/p&gt;
&lt;p&gt;作为易耗品，以后可以考虑在阿里巴巴上买，更便宜。&lt;/p&gt;</description></item><item><title>使用 Homebrew 安装旧版程序</title><link>http://0x3f.org/posts/rollback-to-old-version-with-homebrew/</link><pubDate>Sun, 04 Oct 2020 18:21:04 +0800</pubDate><guid>http://0x3f.org/posts/rollback-to-old-version-with-homebrew/</guid><description>&lt;p&gt;前几天发现因为 Hugo 的不兼容更新导致我在用的主题在部署时报错，所以打算装回旧版。但是网上找到的 Homebrew 回滚方法已过时，新的方法更简单，但找到具体说明也费了点功夫。&lt;/p&gt;
&lt;p&gt;以回滚 Hugo 到 0.74.3 为例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew uninstall hugo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew tap-new donie/hugo-0-74-3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew extract --version 0.74.3 hugo donie/hugo-0-74-3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install hugo@0.74.3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;即：先创建一个名为“donie/hugo-0-74-3”的 tap ，然后通过 extract 命令把相应版本的数据放到里面，就可以安装了。&lt;/p&gt;</description></item><item><title>买了个升降台，开始站立办公</title><link>http://0x3f.org/posts/a-trial-on-standing-desk/</link><pubDate>Fri, 02 Oct 2020 20:31:17 +0800</pubDate><guid>http://0x3f.org/posts/a-trial-on-standing-desk/</guid><description>&lt;p&gt;久坐疲劳，所以打算买个升降台。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="乐歌-m3s"&gt;乐歌 M3S&lt;/h2&gt;
&lt;p&gt;我是个颜党，在所有有白色款的型号里，先选中了造型简约的乐歌 M3S。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20201002204440000-0cd1539def414b5413509e777ba7077a.avif" alt="BE042D7B-24E5-4BFD-A68C-08117A858CE0_1_105_c"&gt;&lt;/p&gt;
&lt;p&gt;实物很重，虽然有些地方稍显粗糙（比如平板插槽底部很粗犷地用热熔胶粘合），但是整体上做工扎实。&lt;/p&gt;
&lt;p&gt;但是试用之后发现一个很严重的问题，Z 形结构虽然美观，但是不够稳定，敲键盘时用力一点就会有明显晃动。&lt;/p&gt;
&lt;h2 id="乐歌-m9s"&gt;乐歌 M9S&lt;/h2&gt;
&lt;p&gt;一开始没有把 X 形结构当做首选是因为感觉不太好看。重新审视后感觉 M9S 观感尚可。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20201002205450000-ddb02cb060b532bedc0f73578e24207f.avif" alt="EB634356-7F03-439D-BC6D-F3CE22C34FCF_1_105_c"&gt;&lt;/p&gt;
&lt;p&gt;实物证明，虽然 X 形结构的美感不如 Z 形，但是稳定性远胜后者。&lt;/p&gt;
&lt;p&gt;M9S 的另一个优点是可以把笔记本电脑放在键盘托上使用。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;当然家里使用还是电动升降桌更好，毕竟桌子上摆这么个庞然大物显得很突兀，而且丧失了其它功能。升降台更适合办公室。&lt;/p&gt;</description></item><item><title>试用讯飞 A1 和 SR101 录音笔</title><link>http://0x3f.org/posts/a-trial-on-iflytec-a1-and-sr101-voice-recorder/</link><pubDate>Mon, 28 Sep 2020 17:30:14 +0800</pubDate><guid>http://0x3f.org/posts/a-trial-on-iflytec-a1-and-sr101-voice-recorder/</guid><description>&lt;p&gt;讯飞的中文语音识别做得很好，十几年前在学校的一次讲座上就见识过讯飞的语音技术，印象深刻。录音笔结合语音识别是现在的一个趋势，把一个比较专业向的工具推向普及，做好了可以是个很有用的效率工具。我曾经跟一些产品经理讲过，如果我是他们，就买一个录音笔，无论是收集、讨论还是评审需求，都是个很好的工具，不至于丢三落四、误人误己。&lt;/p&gt;
&lt;p&gt;讯飞的录音笔包含终身免费的转写服务，是个很吸引人的点。这次试用了 A1 和 SR101 两款，谈谈感受。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="无处安放的-a1"&gt;无处安放的 A1&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200930191238000-f080fa74c7d333cdf2c851d8ecbc58bf.avif" alt="image-20200930191237542"&gt;&lt;/p&gt;
&lt;h3 id="优点"&gt;优点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;工业设计很有特点，外形模仿磁带，附带贴纸，既怀旧又酷炫，属于数码潮玩向的东西。&lt;/li&gt;
&lt;li&gt;体积小巧，火柴盒大小。&lt;/li&gt;
&lt;li&gt;录音效果明显好于 iPhone X。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="特点"&gt;特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过蓝牙和手机传输数据，交互很流畅。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="缺点"&gt;缺点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;不支持待机，5分钟无操作自动关机，不适合做备忘。&lt;/li&gt;
&lt;li&gt;录音过程中不支持做标记，所以不适合做会议记录。&lt;/li&gt;
&lt;li&gt;有安全隐患，手机可以不经授权连接并读取录音笔里的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="总结"&gt;总结&lt;/h3&gt;
&lt;p&gt;几乎完全不满足我的使用场景，所以无处安放。感觉如果能增加标记功能和实现一键录音就值得一用。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="五脏俱全但囿于软件的-sr101"&gt;五脏俱全但囿于软件的 SR101&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200930190135000-c61d417bed66373efe179cde70fb9794.avif" alt="讯飞智能录音笔SR101"&gt;&lt;/p&gt;
&lt;h3 id="优点-1"&gt;优点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;工业设计年轻时尚。&lt;/li&gt;
&lt;li&gt;支持待机、标记、一键录音。&lt;/li&gt;
&lt;li&gt;有屏幕，更方便。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="缺点-1"&gt;缺点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过触屏做标记，误操作的机率很大，影响效率。&lt;/li&gt;
&lt;li&gt;待机状态下，一键录音有3秒左右的等待时间。&lt;/li&gt;
&lt;li&gt;录音数据通过云盘和手机 APP 同步，等待时间超过 A1 很多，极其影响体验。&lt;/li&gt;
&lt;li&gt;录音效果不如 A1。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="总结-1"&gt;总结&lt;/h3&gt;
&lt;p&gt;功能覆盖我的所有需求，但是体验总是离及格线差那么一点。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;讯飞在中文语音识别这个核心技术上的成就勿庸置疑，但是它的产品总是在体验上做得差一点。我用过的讯飞产品里，手机输入法是最接近满意分数线的，但是它的动图搜索功能真的是很反人类，交互很繁复。&lt;/p&gt;
&lt;p&gt;这两款录音笔各自有独特的点、有吸引人的地方，但是最大的短板在软件的体验上，导致不太适合把它们当成效率工具。基于这个出发点，我云了几个设想：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;允许自动转写，目前只能逐条手工操作转写，如果录音较多，会不厌其烦。&lt;/li&gt;
&lt;li&gt;做开放平台，和 IFTTT 之类的服务打通。&lt;/li&gt;
&lt;li&gt;支持 iOS Shortcuts 之类的效率工具。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MySQL 事务的一致性、隔离级别与幻读问题</title><link>http://0x3f.org/posts/isolation-levels-and-phantom-reads-in-mysql/</link><pubDate>Tue, 21 Jul 2020 16:25:09 +0800</pubDate><guid>http://0x3f.org/posts/isolation-levels-and-phantom-reads-in-mysql/</guid><description>&lt;h2 id="数据库事务的一致性"&gt;数据库事务的一致性&lt;/h2&gt;
&lt;p&gt;数据库事务有四个特性：原子性（Atomicity）、一致性（Consistency）、隔离性（Isolation）、持久性（Durability），简称“ACID”。&lt;/p&gt;
&lt;p&gt;其中，“一致性”指的是数据库层面的一致性，与应用层面的一致性不同。&lt;/p&gt;
&lt;p&gt;数据库层面的一致性是说，事务具备把数据库从一个正确的状态迁移到另一个正确的状态的特性。所谓正确的状态，是指任何写入数据库的数据都满足数据库既定的规则，这些规则包括各种约束、级联回滚、触发器以及任何它们的组合。&lt;/p&gt;
&lt;p&gt;与数据库层面的一致性不同，应用层面的一致性要求保证结果的正确性。例如，当执行如下 SQL 语句时：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;我希望最终的结果是在事务开始时 id = 3 的这行数据 balance 列的值的基础上加一，否则，结果就是不正确的。&lt;/p&gt;
&lt;p&gt;因此，只要写入的数据满足数据库的规则，就保证了数据库层面的一致性。&lt;strong&gt;数据库层面的一致性并不保证数据正确&lt;/strong&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;h2 id="mysql-事务的隔离级别与幻读问题"&gt;MySQL 事务的隔离级别与幻读问题&lt;/h2&gt;
&lt;h3 id="隔离级别"&gt;隔离级别&lt;/h3&gt;
&lt;p&gt;隔离性是指：多个事务并发执行时，每个事务对数据库所做的更改必须与其它事务隔离。&lt;/p&gt;
&lt;p&gt;隔离性是并发控制的主要目标&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;，并发控制用来实现在保证应用层面一致性的前提下，尽可能快地对并发请求做出响应。由此可见，隔离性和并发能力是一对此消彼长的关系。极端情况下，如果并发的请求按顺序执行，隔离性是最好的，但是响应最慢，反之亦然。&lt;/p&gt;
&lt;p&gt;在此基础上，产生了四个隔离级别的划分。由低到高依次为：读未提交、读已提交、可重复读、序列化。据前所述，它们的并发能力是依次下降的。&lt;/p&gt;
&lt;p&gt;因此，&lt;strong&gt;隔离级别的本质是通过适度地破坏隔离性来提高并发能力。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="隔离级别的问题"&gt;隔离级别的问题&lt;/h3&gt;
&lt;p&gt;隔离级别不同，存在的问题也不一样。&lt;/p&gt;
&lt;p&gt;“读未提交”的级别最低、并发能力最高，存在的问题也最多，包括：脏读、不可重复读、幻读。其中，脏读是这个级别独有的，即事务 A 读取了并发事务 B 未提交的数据。&lt;/p&gt;
&lt;p&gt;“读已提交”顾名思义，事务 A 不会读取并发事务 B 未提交的数据，但可以读取其已提交的。因此，这个级别存在不可重复读和幻读的问题。&lt;/p&gt;
&lt;p&gt;在“可重复读”级别下，同一事务中两次同样的查询结果一致，不会受并发事务的影响，它因此也解决了不可重复读的问题。但还会存在幻读问题。&lt;/p&gt;
&lt;p&gt;“序列化”级别要求对查询的对象加范围锁并保持到事务结束，因此，它避免了幻读的问题。&lt;/p&gt;
&lt;h3 id="幻读问题phantom-reads"&gt;幻读问题（Phantom Reads）&lt;/h3&gt;
&lt;p&gt;幻读问题是个很 tricky 的问题，以至于网上找到的很多文章对它的理解都是不全面甚至是错误的。&lt;/p&gt;
&lt;p&gt;幻读即同一事务中两次相同查询的结果集不一致。乍一看，好像和不可重复读是一样的。那它们的区别是什么呢？&lt;/p&gt;
&lt;p&gt;事实上，幻读是不可重复读的一种特殊情况。换句话说，&lt;strong&gt;只要存在幻行（Phantom Rows），就是幻读问题&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;所谓幻行，即同一事务中两次相同的查询结果集的非空差集里的元素，或者说第二次查询后发现不存在于前一次结果集中的行。&lt;/p&gt;
&lt;p&gt;幻行产生的原因主要是除“序列化”之外的隔离级别不要求对查询结果加范围锁，导致并发事务在查询范围内插入新的行后被当前事务查到。&lt;/p&gt;
&lt;h4 id="mvcc"&gt;MVCC&lt;/h4&gt;
&lt;p&gt;在此基础上，MySQL 的 InnoDB 引擎实现了“多版本并发控制”（MVCC: Multiversion Concurrency Control）。&lt;/p&gt;
&lt;p&gt;简单地说，InnoDB 的表存在两个隐藏列，用于记录每行数据的版本信息。当插入一行数据时，InnoDB 将当前事务的版本信息一并写入。当修改一行数据时，InnoDB 先将该行做一次复制，并把当前版本信息写入进去。查询时，只返回版本小于等于当前事务版本的数据。通过这样保证一个事务中查询到的是事务开始前已经存在的数据或当前事务写入的数据。其它事务写入的数据则不会被读取。&lt;/p&gt;</description></item><item><title>MacBook Pro 维修记</title><link>http://0x3f.org/posts/story-of-repairing-macbook-pro/</link><pubDate>Fri, 26 Jun 2020 23:29:24 +0800</pubDate><guid>http://0x3f.org/posts/story-of-repairing-macbook-pro/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200626233649000-20a04d7122017dad4685781e5c694fba.avif" alt="img"&gt;&lt;/p&gt;
&lt;p&gt;生平第一次修电脑。&lt;/p&gt;
&lt;p&gt;17款的 MacBook Pro 13`，该有的问题全有——键盘随机连击或无反应、在桌面上放不平且触控板反馈很弱、疑似电池鼓包。&lt;/p&gt;
&lt;p&gt;用过 ThinkPad X200 和 X220，虽然屏幕很渣，但从来没出过问题。上一台电脑是 15 款的 MacBook Air，用了三年，也没事儿。只能说这届苹果不行。&lt;/p&gt;
&lt;p&gt;APP 上预约的三里屯店，时间下午两点多。太古里门口和店门口分别出示了一次健康码。虽然是工作日、而且在疫情期间，店里人不多也不少，还是等了一会儿。&lt;/p&gt;
&lt;p&gt;常规的询问和联机检查，大概花了十几分钟，没有要求提供任何凭证。店员说因为键盘和电池都在一起，所以是要一块换的。时间上快则一天，慢则两三天，就能修好。&lt;/p&gt;
&lt;p&gt;第二天晚上九点半，接到一个陌生座机号码打来的电话，以为是营销电话，而且之前看过有说换键盘用了一周时间的帖子，所以没往这上面想，就没接。&lt;/p&gt;
&lt;p&gt;第三天晚上看手机电池健康状态的时候，偶然看到电脑的维修状态是已完成，才意识到，回电话过去果然是三里屯苹果商店，但是没人接。&lt;/p&gt;
&lt;p&gt;今天早上九点多，再次打过去，说是十点才营业。于是决定直接过去。&lt;/p&gt;
&lt;p&gt;交接需要出示身份证，花了几分钟验机，很快结束。期间问店员如果之后键盘再坏了怎么办，说是有一年保修期，而且因为批次不同的原因，换过的键盘不容易再出问题。暗笑，换个批次就能解决的话，新款何至于换回剪刀脚？！&lt;/p&gt;
&lt;p&gt;回家后用了一会儿，新键盘和触控板体验很棒，没有打油的阻尼感沁人心脾，发了条 tweet 说：找回了初恋的感觉。&lt;/p&gt;</description></item><item><title>从 Hexo 到 Hugo</title><link>http://0x3f.org/posts/migrate-from-hexo-to-hugo/</link><pubDate>Fri, 19 Jun 2020 17:41:52 +0800</pubDate><guid>http://0x3f.org/posts/migrate-from-hexo-to-hugo/</guid><description>&lt;p&gt;一切源于我这个颜党的喜新厌旧。&lt;/p&gt;
&lt;p&gt;总想找到一个极简而不失现代感的主题，在这个过程中，发现越来越多比较贴近我口味的主题都是适配 Hugo 的。趁最近有时间，就换了过来。&lt;/p&gt;</description></item><item><title>用 SSH 命令调试 Git 的连接问题</title><link>http://0x3f.org/posts/debug-git-connection-with-ssh/</link><pubDate>Sat, 28 Mar 2020 23:17:45 +0000</pubDate><guid>http://0x3f.org/posts/debug-git-connection-with-ssh/</guid><description>&lt;p&gt;昨天执行&lt;code&gt;git pull&lt;/code&gt;的时候发现会一直卡在那儿，排除了各种可能，而且 Github 上的项目也是可以正常拉取的，说明跟网络、代理等关系应该不大，git 命令本身也工作正常。&lt;/p&gt;
&lt;p&gt;问题集中在公司的项目上，所有项目都无法拉取代码。起先怀疑是公司自建的 Gitlab 出了问题，但是其他人那里又是正常的，甚至跟我同一局域网的电脑上也是正常的。&lt;/p&gt;
&lt;p&gt;也就是说问题应该出在我自己的电脑上。考虑到前两天还能正常使用，之后唯一一件相关的事就是升级 macOS 到 10.15.4 了。&lt;/p&gt;
&lt;p&gt;然而用 Homebrew 重新安装 git 等相关的几个包也没能解决问题，于是用&lt;code&gt;ssh -T -v git@gitlab.xxx.com -p 8848&lt;/code&gt;调试，输出如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;donie@Donies  ~  ssh -T -v git@gitlab.xxx.com -p 8848
OpenSSH_8.1p1, LibreSSL 2.7.3
debug1: Reading configuration data /Users/donie/.ssh/config
debug1: /Users/donie/.ssh/config line 9: Applying options for gitlab.xxx.com
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 47: Applying options for *
debug1: Connecting to gitlab.xxx.com port 8848.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;卡在了“Connecting to gitlab.xxx.com port 8848”这一步，但是&lt;code&gt;telnet gitlab.xxx.com 8848&lt;/code&gt;却是通的。&lt;/p&gt;</description></item><item><title>改变 Vim 模式时自动切换输入法的方法</title><link>http://0x3f.org/posts/auto-switch-input-method-while-changing-vim-mode/</link><pubDate>Wed, 19 Feb 2020 21:48:15 +0000</pubDate><guid>http://0x3f.org/posts/auto-switch-input-method-while-changing-vim-mode/</guid><description>&lt;p&gt;VS Code的Vim插件有个很贴心的功能，可以在切换到普通模式时自动切换到英文输入法，而当切换回插入模式时再换到此前的输入法。&lt;/p&gt;
&lt;p&gt;设置的方法很简单。先安装&lt;a href="https://github.com/daipeihust/im-select"&gt;im-select&lt;/a&gt;，然后配置如下（macOS）：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200219215902000-1bbeb5210a8d458f4edf04b617e0b0ea.avif" alt="2020-02-19-21-59-02-510Ak5"&gt;&lt;/p&gt;
&lt;p&gt;当然，在Vim里也可以利用im-select实现这个功能。&lt;/p&gt;</description></item><item><title>在 VS Code 中快速创建 PHPUnit 测试类的方法</title><link>http://0x3f.org/posts/quickly-create-phpunit-test-cases-with-vscode/</link><pubDate>Tue, 18 Feb 2020 22:49:45 +0000</pubDate><guid>http://0x3f.org/posts/quickly-create-phpunit-test-cases-with-vscode/</guid><description>&lt;p&gt;通过单元测试解决问题或者调试代码，可以避开错综复杂的依赖关系、直击问题的核心，从而极大地节约时间、提高效率。&lt;/p&gt;
&lt;p&gt;但是，当创建测试类成为一个经常发生的操作时，每次都手动创建类、引入基类、添加测试方法就显得很烦琐。我需要这样一个解决方案，让我可以立即开始着手写测试代码。&lt;/p&gt;</description></item><item><title>用Github当图床</title><link>http://0x3f.org/posts/take-github-as-image-hosting-service/</link><pubDate>Thu, 06 Feb 2020 22:00:00 +0000</pubDate><guid>http://0x3f.org/posts/take-github-as-image-hosting-service/</guid><description>&lt;p&gt;微博图床的域名不知道什么时候改了，Google找不到相关信息，经过排查发现原域名中的“ws”改成了“wx”，浪费了不少时间。&lt;/p&gt;
&lt;p&gt;于是打算换图床。&lt;/p&gt;</description></item><item><title>关于Lumen的Facade不支持引用传递的看法</title><link>http://0x3f.org/posts/lumen-facade-doesnot-support-pass-by-reference-param/</link><pubDate>Tue, 04 Feb 2020 17:40:34 +0000</pubDate><guid>http://0x3f.org/posts/lumen-facade-doesnot-support-pass-by-reference-param/</guid><description>&lt;p&gt;今天遇到一个奇怪的问题，一次调用带引用传递形参的方法后，该形参对应的变量值没有按预期改变。&lt;/p&gt;</description></item><item><title>用C4-PlantUML画软件架构图</title><link>http://0x3f.org/posts/design-software-architecture-with-c4-plantuml/</link><pubDate>Fri, 17 Jan 2020 17:29:24 +0000</pubDate><guid>http://0x3f.org/posts/design-software-architecture-with-c4-plantuml/</guid><description>&lt;p&gt;&lt;a href="https://c4model.com"&gt;C4 Model&lt;/a&gt;是一种简洁有序的架构模型，四个“C”分别表示“Context”、“Container”、“Component”和“Code”，是由上而下逐步细化的四个层级。&lt;/p&gt;</description></item><item><title>用鼠须管输入日期时间的方法</title><link>http://0x3f.org/posts/input-date-and-time-with-rime/</link><pubDate>Wed, 08 Jan 2020 13:52:49 +0000</pubDate><guid>http://0x3f.org/posts/input-date-and-time-with-rime/</guid><description>&lt;p&gt;原来在Linux下用小小输入法，输入日期时间很方便。换到Mac后，很早就在关注这个问题，直到后来鼠须管实现了嵌入Lua脚本的功能才得以解决。&lt;/p&gt;</description></item><item><title>用 PlantUML 实现 ERD</title><link>http://0x3f.org/posts/plantuml-erd/</link><pubDate>Fri, 03 Jan 2020 17:01:41 +0000</pubDate><guid>http://0x3f.org/posts/plantuml-erd/</guid><description>&lt;p&gt;很长一段时间，我们都在用 MySQLWorkbench 画 ER 图。但是这个东西有一些缺陷，导致体验很不好。&lt;/p&gt;
&lt;p&gt;首先它生成的文件是二进制的，做不了版本控制。这意味着在版本迭代的过程中做数据结构评审的体验很糟糕。其次，离线文件难以管理，不利于团队协作。第三，图形界面虽然简单，但并不等价于高效。用它画图的成本还是比较高的。&lt;/p&gt;
&lt;p&gt;PlantUML 是个基于文本、灵活且强大的 UML 画图工具，高度可定制，而且可以集成到多种开发工具中。主流的 IDE 、文本编辑器都可以集成 PlantUML ，以便用自己最熟悉的工具画图并实时预览。基于文本的特性使得版本控制和 Code Review 很容易实现。如果 VCS 用的是 Gitlab ，可以更进一步，借助 PlantUML Server 实现实时预览。即使对于像 Github 这种暂时没有提供支持的 Web 平台，也有变通的解决方案。&lt;/p&gt;</description></item><item><title>AirPods Pro的使用感受</title><link>http://0x3f.org/posts/the-expirence-of-airpods-pro/</link><pubDate>Tue, 05 Nov 2019 16:18:54 +0000</pubDate><guid>http://0x3f.org/posts/the-expirence-of-airpods-pro/</guid><description>&lt;p&gt;Bose QC35曾是带给我巨大幸福感的工具，并且三年来一直处于重度使用的状态。但是它的一些弱点，使得在某些细分场景下并不能得到很好的体验。首先是包耳式的设计在夏天会很热。其次，虽然有折叠的功能，但头戴式的设计对于日常通勤来说，还是不够便携。再次，QC35一代的降噪级别只能通过APP设置，很麻烦，所以我一直都保持默认开启状态，出于安全性考虑，不适合徒步或者骑行。&lt;/p&gt;
&lt;p&gt;于是后来买了一副AirPods（以下简称AP）。高温和骑行的体验得以改善，但一直被通勤过程中北京公交糟糕的乘坐体验所困扰。其实在购买AP之前，更想买的是带降噪功能的耳塞，当时索尼的降噪豆一代才刚上市，评测普遍反馈体验不太好，而QC30的狗圈又让我完全接受不能，除此之外，在当时并无更多的选择。AP其实是权衡之后妥协的结果。&lt;/p&gt;
&lt;p&gt;所以从看到AirPods Pro（以下简称APP）上市的消息到下单，并没有考虑太久。下单时提示可能一到两周才能到货，但其实第二天就发了货，次日到手。体验了几天，说说感受。&lt;/p&gt;</description></item><item><title>解决Laravel中makeWith()无法取到被mock的实例的问题</title><link>http://0x3f.org/posts/mocking-objects-made-by-laravel-container-with-parameters/</link><pubDate>Fri, 16 Aug 2019 10:55:40 +0000</pubDate><guid>http://0x3f.org/posts/mocking-objects-made-by-laravel-container-with-parameters/</guid><description>&lt;p&gt;被测单元有一行实例化一个类的代码，而且该类的构造方法需要参数。基于面向单元测试编程的原则，通过容器的makeWith()方法实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;makeWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Api&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;config&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但是在执行单元测试时发现，虽然测试代码中已经mock了这个类且注入到容器，但在被测单元中取到的还是原类的实例。&lt;/p&gt;</description></item><item><title>利用单元测试为开发提效</title><link>http://0x3f.org/posts/use-unit-test-as-an-efficiency-tool/</link><pubDate>Tue, 13 Aug 2019 16:38:02 +0000</pubDate><guid>http://0x3f.org/posts/use-unit-test-as-an-efficiency-tool/</guid><description>&lt;p&gt;单元测试可以方便地伪造和回滚测试数据，这个特性决定了它其实是一个效率工具。&lt;/p&gt;
&lt;p&gt;例如在开发退款单、发票的时候，由于这种后置的功能依赖订单、支付、库存等前置的数据，因此需要频繁地创建这些测试数据，这就导致开发的效率极低，有时甚至需要切换多个系统做诸如增加库存、下单、支付等操作。虽然在开发环境可以通过直接修改数据使之恢复可被测试的状态，但仍然存在效率很低、遗留垃圾数据和存在隐患等问题。&lt;/p&gt;
&lt;p&gt;单元测试可以完美地解决这些问题。&lt;/p&gt;</description></item><item><title>面向单元测试编程</title><link>http://0x3f.org/posts/unit-test-oriented-programming/</link><pubDate>Tue, 13 Aug 2019 16:35:15 +0000</pubDate><guid>http://0x3f.org/posts/unit-test-oriented-programming/</guid><description>&lt;p&gt;同一逻辑可以有多种实现方式，选择对单元测试友好的方式可以提高写测试代码的效率。&lt;/p&gt;</description></item><item><title>PHP单元测试的技巧</title><link>http://0x3f.org/posts/phpunit-tips/</link><pubDate>Tue, 13 Aug 2019 14:21:48 +0000</pubDate><guid>http://0x3f.org/posts/phpunit-tips/</guid><description>&lt;p&gt;以下是我平时写单元测试时总结的一些最佳实践，有些是和具体的框架强相关的。&lt;/p&gt;</description></item><item><title>Lumen单元测试提示自定义校验规则不存在的问题</title><link>http://0x3f.org/posts/unit-test-in-laravel-complains-validation-rule-not-exist/</link><pubDate>Fri, 02 Aug 2019 15:12:17 +0000</pubDate><guid>http://0x3f.org/posts/unit-test-in-laravel-complains-validation-rule-not-exist/</guid><description>&lt;p&gt;执行单元测试时遇到报错：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;BadMethodCallException: Method [validateIdList] does not exist.
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>对比Laravel Excel和Spout的读写性能</title><link>http://0x3f.org/posts/performance-comparation-for-laravel-excel-and-spout/</link><pubDate>Sun, 07 Jul 2019 20:23:26 +0000</pubDate><guid>http://0x3f.org/posts/performance-comparation-for-laravel-excel-and-spout/</guid><description>&lt;pre tabindex="0"&gt;&lt;code&gt;./artisan excel:write --driver=spout --amount=100000
写入数据100000行。
用时：156秒。
最大使用内存：2750.5106964111 M。
./artisan excel:write --driver=laravel-excel --amount=100000
写入数据100000行。
用时：305秒。
最大使用内存：1330.7370758057 M。
./artisan excel:read ./storage/app/test.xlsx --driver=spout
读取数据100001行。
用时：576秒。
最大使用内存：122.15303039551 M。
./artisan excel:read ./storage/app/test.xlsx --driver=laravel-excel
读取数据100001行。
用时：166秒。
最大使用内存：739.48976898193 M。
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;基本上，Laravel Excel写XLSX的性能是Spout的一半，但内存占用是对方的一半。而在读文件上，前者的性能是后者的约3倍多，而内存占用是后者的6倍。&lt;/p&gt;
&lt;p&gt;测试环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MBP 3.1 GHz Intel Core i5 8G内存&lt;/li&gt;
&lt;li&gt;PHP 7.1.30&lt;/li&gt;
&lt;li&gt;Laravel 5.8.27&lt;/li&gt;
&lt;li&gt;Laravel Excel 3.1.14&lt;/li&gt;
&lt;li&gt;Spout 3.0.1&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>《Clean Code》第十四章读后</title><link>http://0x3f.org/posts/after-reading-chapter-14-of-clean-code/</link><pubDate>Mon, 20 May 2019 23:48:41 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-chapter-14-of-clean-code/</guid><description>&lt;p&gt;蹩脚的译文看着实在费解，干脆去看《Clean Code》的原版。第14章“Successive Refinement（逐步改进）”讲的是对一个用Java实现的解析命令行参数的类Args重构的过程。&lt;/p&gt;
&lt;p&gt;很多人都应该好好看看这章。&lt;/p&gt;</description></item><item><title>Git工作流调研报告</title><link>http://0x3f.org/posts/investigation-report-of-git-flows/</link><pubDate>Wed, 15 May 2019 16:14:17 +0000</pubDate><guid>http://0x3f.org/posts/investigation-report-of-git-flows/</guid><description>&lt;h2 id="面临的问题"&gt;面临的问题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;测试环境杂乱导致的问题&lt;/p&gt;
&lt;p&gt;每个任务都要搭建测试环境，或者把闲置的测试环境切换到待测试分支。麻烦，而且容易出问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;抢占beta环境的问题&lt;/p&gt;
&lt;p&gt;每个任务部署到beta环境时都要和别人确认，同时其它任务都要等待。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上线任务A把尚在测试中的任务B的部分代码部署上线的问题&lt;/p&gt;
&lt;p&gt;先把feature分支合并到master分支，再部署到beta环境。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;任务A和B在逻辑上互斥或者代码有冲突，导致问题在上线后才发现&lt;/p&gt;
&lt;p&gt;测试阶段是针对每个feature分支测试，而不是针对一个集成的分支。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不能保证所有上线的代码都经过测试&lt;/p&gt;
&lt;p&gt;直接把feature分支合并到master分支，不能保证所有代码都经过测试。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>基于Laravel的项目的单元测试规范</title><link>http://0x3f.org/posts/unit-testing-standard-for-laravel-based-projects/</link><pubDate>Sun, 24 Mar 2019 22:42:08 +0000</pubDate><guid>http://0x3f.org/posts/unit-testing-standard-for-laravel-based-projects/</guid><description>&lt;p&gt;单元测试是个好东西，解决了我很多问题，不论开发效率还是代码质量，都给我助益良多。最近想在团队内部推广，就拟了个规范草稿：&lt;/p&gt;</description></item><item><title>用ALE替换了Syntastic</title><link>http://0x3f.org/posts/replace-syntastic-with-ale/</link><pubDate>Wed, 12 Dec 2018 20:42:10 +0000</pubDate><guid>http://0x3f.org/posts/replace-syntastic-with-ale/</guid><description>&lt;p&gt;习惯频繁地保存源码，但是每次保存都有明显的卡顿，于是用Vim自己的调优功能跟踪了一下。&lt;/p&gt;</description></item><item><title>配置鼠须管的特殊符号输入</title><link>http://0x3f.org/posts/input-punctuations-with-rime/</link><pubDate>Sat, 13 Oct 2018 11:59:50 +0000</pubDate><guid>http://0x3f.org/posts/input-punctuations-with-rime/</guid><description>&lt;p&gt;&lt;em&gt;开源工具最常见的问题就是文档不全，实现一个需求的时候只能苦苦Google，甚至连蒙带猜。这也是我逐渐倾向买用户体验更好的收费软件的原因。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;鼠须管是自带特殊符号码表的，在用户配置目录中的&lt;code&gt;symbols.yaml&lt;/code&gt;，但是有的码表需要手动配置。经过查资料和摸索，关键在于以下几项配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;punctuator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;import_preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;symbols&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;recognizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;import_preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;default&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;punct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;^/([a-z]+|[0-9]0?)$&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后就可以通过&lt;code&gt;【/】+【编码】&lt;/code&gt;的方式显示符号备选项了，具体的编码可以到&lt;code&gt;symbols.yaml&lt;/code&gt;里看，当然一般为了方便定制该码表，会复制并重命名该文件，然后上述的配置项里也要做相应的修改。&lt;/p&gt;</description></item><item><title>我叫王战斗</title><link>http://0x3f.org/posts/i-am-wang-zhandou/</link><pubDate>Sun, 01 Jul 2018 16:46:32 +0000</pubDate><guid>http://0x3f.org/posts/i-am-wang-zhandou/</guid><description>&lt;p&gt;我叫王战斗，男，喵星人，狸花族，现年四个半月，折合成你们两脚兽的年龄算7岁了。&lt;/p&gt;
&lt;p&gt;虽然刚降临你星不久，但是我已经能驯服和驾驭两脚兽这种低等生物了。因为我发现这种生物本性里有一个致命弱点：对它很好反而不会珍惜，故作高冷却奴颜婢膝求抱抱！我们喵星管这叫「贱」。&lt;/p&gt;
&lt;p&gt;开始的时候，我的驭兽术还不熟练，而且我酷爱往两脚兽的脖子里钻，然后蹭它们的脸。结果它们不干了，在我才两个月零九天的时候就把我交给了现在这头两脚兽。是它们不懂喵星习俗好不好？！而且作为一个刚断奶的小正太，卖个萌怎么啦，怪我咯？&lt;/p&gt;
&lt;p&gt;我一直在暗中观察现在这头两脚兽。发现每隔五天，它都会在巢穴里待上两天，然后在接下来的五天里每天都消失一段时间。虽然有点好奇，不过也不是什么大事，只要我有吃有喝、两脚兽按时铲屎，每天给它放个风什么的我也OK，这是我们喵星高等生物的自我修养。&lt;/p&gt;
&lt;p&gt;不过还是要测试一下这货的驯服度。所以我命令它伺候我睡个午觉：
&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvx0d5683j31kw1kwb29.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这货竟然没有反抗！！！&lt;/p&gt;
&lt;p&gt;有一天我发现它竟然在偷看我练习家传绝学「黑虎掏心」，我就瞪它，就瞪它：
&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx0z5chyj31ei1ei4qp.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;有时候两脚兽全神贯注地照镜子，我就想看看它看的啥，然后它就扒拉我，我想一定是我高大威猛的身躯挡住它了：
&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvx1dzxegj31kw16okjm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这老头叫马霸霸，挺能白话的，它的巢穴已经被我军占领了：
&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx1v8jh3j31kw1kwhdu.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;那天两脚兽带回来一只老鼠，我一眼就看出来是假的，但是这货一碰就叫啊，然后我就停不下来了，你星管这叫口嫌体正直，看著两脚兽谜之微笑，我觉得中了奸计：
&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvx2fq5ltj30sz0prq8x.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;更有甚者，它竟然趁我睡著的时候拍我裸照，还传到网上：
&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx2ix4jej31kw23ve84.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;生亦何欢，死亦何惧。趁两脚兽上厕所的时候，叼走了卷纸，然后撕稀碎，有能耐学我们喵星人上完厕所自己舔干净啊？！
&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvx2zgpawj31kw1kw1kz.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;没想到报复来得如此突然，两脚兽不知道从哪儿搞了一瓶毒气，走到哪儿揣到哪儿，我一想搞事情就各种喷：
&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvx332k34j30lc0sgn0a.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;真臭啊，臭到怀疑喵生啊！
&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx3jj4ktj31kw23v1kz.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;话说回来，大部分时间两脚兽还是没那么讨厌。比如这个会喷水的盒子，被我霸占后就成了我最常喝水的东西兼洗脚盆：
&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvxatojbkj31260v9k0s.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;两脚兽的厨艺也不赖：
&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvxb51icjj31kw1kw1kz.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;吹嘘自己慷慨的时候，两脚兽就指著这口袋说：「比我吃得都好。」其实就是618的打折货。
&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvx61t9ogj31kw1kw1kz.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;两脚兽就是个肥宅兼Nerd，且不说为了给我做饭专门买了台电动切碎机和保鲜盒。铲个屎都装绝命毒师：
&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvx6f8zwzj31kw14fhdv.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;某天整了把稀奇古怪的东西在床上、沙发上各种吸，完事非要说是我干的：
&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvx709q7qj31kw16o4qq.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我的天啊！不就掉个毛么，全宇宙只有你们两脚兽光著屁股满世界跑！
&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx75b1f9j31kw1kw7wi.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我来，我见，我征服。我是王战斗，一个普通的驯兽师。
&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvx7kbr2hj30sg0sg0zr.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>生成PDF的方案调研</title><link>http://0x3f.org/posts/pdf-creating-solutions/</link><pubDate>Wed, 16 May 2018 15:41:36 +0000</pubDate><guid>http://0x3f.org/posts/pdf-creating-solutions/</guid><description>&lt;h2 id="结论"&gt;结论&lt;/h2&gt;
&lt;p&gt;倾向于通过wkhtmltopdf+消息队列实现。&lt;/p&gt;
&lt;p&gt;工作流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用户保存表单&lt;/li&gt;
&lt;li&gt;推送生成pdf的任务到队列&lt;/li&gt;
&lt;li&gt;同时页面显示「正在生成PDF文档，请稍候」并轮询后端接口&lt;/li&gt;
&lt;li&gt;PDF生成后，页面显示下载按钮&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="后端"&gt;后端&lt;/h2&gt;
&lt;h3 id="dompdf"&gt;dompdf&lt;/h3&gt;
&lt;p&gt;纯PHP实现。工作原理是把HTML转换成PDF。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不需要PHP调用命令行，安全性高。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTML/CSS支持不完全，实测多个网页转换后排版错乱。&lt;/li&gt;
&lt;li&gt;中文网页转换后，中文都是问号（网上说有解决办法&lt;a href="http://www.cnblogs.com/xxoome/p/6083542.html"&gt;1&lt;/a&gt;、&lt;a href="http://blog.51cto.com/lampzxr/1916038"&gt;2&lt;/a&gt;，未测试）。&lt;/li&gt;
&lt;li&gt;CPU占用比较高（网上的说法，没有实测具体有多高）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https///github.com/barryvdh/laravel-dompdf"&gt;laravel-dompdf主页&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mpdf"&gt;mpdf&lt;/h3&gt;
&lt;p&gt;纯PHP实现。工作原理是把HTML转换成PDF。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不需要PHP调用命令行，安全性高。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;缺点（未实测）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTML/CSS支持不完整。&lt;/li&gt;
&lt;li&gt;生成PDF耗时长。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https///github.com/niklasravnsborg/laravel-pdf"&gt;laravel-pdf主页&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https///mpdf.github.io"&gt;mpdf文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https///github.com/mpdf/mpdf"&gt;mpdf主页&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cnblogs.com/attitudeY/p/7297948.html"&gt;mpdf与fpdf的使用比较&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="pdftk-server"&gt;PDFtk Server&lt;/h3&gt;
&lt;p&gt;PDFtk Server是个命令行程序。工作原理是利用FDF表单替换PDF模板中的占位符。实现方案有：纯PHP实现FDF + PDFtk、FPDI + PDFtk。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;直接替换PDF模板，实现成本低，最大程度保证生成的PDF的效果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;需要允许PHP调用命令行，有安全隐患。&lt;/li&gt;
&lt;li&gt;只能实现简单的字符串替换（例如公司名称），不能替换有格式文本。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https///www.setasign.com/products/fpdi/manual/#p-58"&gt;FPDI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://php.net/manual/zh/intro.fdf.php"&gt;PHP的FDF手册&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https///stackoverflow.com/questions/1389964/merge-fdf-data-into-a-pdf-file-using-php"&gt;PDFtk的使用方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https///www.sitepoint.com/filling-pdf-forms-pdftk-php/"&gt;纯PHP实现FDF + PDFtk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="wkhtmltopdf"&gt;wkhtmltopdf&lt;/h3&gt;
&lt;p&gt;wkhtmltopdf是个命令行程序。工作原理是转换HTML到PDF。实现方案是laravel-snappy。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;由于内嵌webkit核心，HTML/CSS的支持没有问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;需要允许PHP调用命令行，有安全隐患。&lt;/li&gt;
&lt;li&gt;wkhtmltopdf体积40M，并发较多时影响服务器性能和稳定性（需要考虑用队列辅助实现，异步执行，需要需求变更交互方式）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https///github.com/barryvdh/laravel-snappy"&gt;laravel-snappy主页&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cutycapt"&gt;CutyCapt&lt;/h3&gt;
&lt;p&gt;命令行程序。工作原理和wkhtmtopdf相同。&lt;/p&gt;
&lt;p&gt;优缺点同wkhtmltopdf，但是最近的更新在13年。&lt;/p&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://cutycapt.sourceforge.net"&gt;CutyCapt主页&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="prince"&gt;Prince&lt;/h3&gt;
&lt;p&gt;命令行程序。工作原理是转换HTML到PDF。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTML/CSS的支持很好。&lt;/li&gt;
&lt;li&gt;文档很全&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;缺点：&lt;/p&gt;</description></item><item><title>鼠须管的美化</title><link>http://0x3f.org/posts/beautify-squrrel-input-method/</link><pubDate>Sat, 21 Apr 2018 20:52:42 +0000</pubDate><guid>http://0x3f.org/posts/beautify-squrrel-input-method/</guid><description>&lt;p&gt;效果如下：
&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvx9h8tgtj30n20bqaah.jpg" alt="Ulysses_2018-04-21 20-43-42@2x"&gt;&lt;/p&gt;
&lt;p&gt;尽管鼠须管的Github仓库一直在更新，但释出版已经很久没有更新了，所以下面的美化基于网络上个人编译的版本。&lt;a href="https://scomper.me/gtd/-shu-xu-guan-de-diao-jiao-bi-ji"&gt;这篇文章&lt;/a&gt;里有该版本和「花园明朝」字体的下载链接，按照文中的说明替换鼠须管的程序。（&lt;em&gt;注意：官方当前释出版本鼠须管不支持下文通过patch自定义配置的方式，会造成原配置信息丢失。也不支持图示的样式。&lt;/em&gt;）&lt;/p&gt;
&lt;p&gt;然后参考&lt;a href="https://scomper.me/gtd/shu-xu-guan-shu-ru-fa-de-xin-pei-se"&gt;这篇文章&lt;/a&gt;，把新的颜色方案移植到用户配置中。&lt;/p&gt;
&lt;p&gt;图示样式使用「dust」方案。原色彩方案的字体设置的有点小，需要把font_point和label_font_point分别从14和10修改成18和14。原方案的第一顺序字体是「HYQiHei-55S Book」，要使用图示的花园明朝字体，可以不安装或者从配置信息中去掉该字体。由于原方案中已存在的配置项不能通过patch的方式覆盖，所以只能直接修改squirrel.yaml文件。&lt;/p&gt;</description></item><item><title>我在用的Safari扩展</title><link>http://0x3f.org/posts/the-safari-extensions-i-am-using/</link><pubDate>Sun, 15 Apr 2018 22:29:10 +0000</pubDate><guid>http://0x3f.org/posts/the-safari-extensions-i-am-using/</guid><description>&lt;p&gt;和Chrome相比，Safari更省电、需要更少的系统资源，而且Chrome还有一些莫名其妙的问题，比如在没有运行的时候，从Alfred执行搜索会启动两个窗口，一个是之前的会话，另一个是当前的搜索页面。并且，启用了一些扩展之后Safari的体验可以改进很多。所以平时用Safari更多一些。&lt;/p&gt;
&lt;h2 id="svim"&gt;sVim&lt;/h2&gt;
&lt;p&gt;作为注重效率的Vim党和键盘党，这种扩展是使用任何浏览器必备的东西。最常用的就是用标记打开链接的功能。&lt;/p&gt;
&lt;h2 id="tampermonkey"&gt;Tampermonkey&lt;/h2&gt;
&lt;p&gt;油猴脚本管理器，应该是任何浏览器必备的东西。&lt;/p&gt;
&lt;h2 id="autopagerize"&gt;AutoPagerize&lt;/h2&gt;
&lt;p&gt;用Google搜索时自动滚动到下一页。&lt;/p&gt;
&lt;h2 id="rss-menu"&gt;RSS Menu&lt;/h2&gt;
&lt;p&gt;当发现当前页面有可订阅的RSS链接时，在工具栏图标上显示提示。&lt;/p&gt;
&lt;h2 id="instapaper"&gt;Instapaper&lt;/h2&gt;
&lt;p&gt;稍后读工具。&lt;/p&gt;
&lt;h2 id="turn-off-the-lights"&gt;Turn Off the Lights&lt;/h2&gt;
&lt;p&gt;看视频时降低网页其余部分亮度。&lt;/p&gt;
&lt;h2 id="scroll-to-top-button"&gt;Scroll To Top Button&lt;/h2&gt;
&lt;p&gt;在页面右下角显示一个浮动的跳转到页首按钮。&lt;/p&gt;
&lt;h2 id="push-for-kindle"&gt;Push for Kindle&lt;/h2&gt;
&lt;p&gt;FiveFilters.org的发送到Kindle按钮。&lt;/p&gt;
&lt;h2 id="octotree"&gt;octotree&lt;/h2&gt;
&lt;p&gt;GitHub侧边栏。&lt;/p&gt;
&lt;h2 id="translate"&gt;Translate&lt;/h2&gt;
&lt;p&gt;翻译当前页。&lt;/p&gt;
&lt;h2 id="wikiwand"&gt;WikiWand&lt;/h2&gt;
&lt;p&gt;优化维基百科阅读体验。&lt;/p&gt;
&lt;h2 id="xdebug-helper"&gt;Xdebug Helper&lt;/h2&gt;
&lt;p&gt;PHP单步调试辅助工具。&lt;/p&gt;
&lt;h2 id="adblock"&gt;AdBlock&lt;/h2&gt;
&lt;p&gt;广告过滤器。&lt;/p&gt;
&lt;h2 id="sessions"&gt;Sessions&lt;/h2&gt;
&lt;p&gt;网页会话管理器。如果打开的页面太多，又可能在将来再用到，可以保存会话后清理掉，用到的时候再打开保存过的会话。虽然没有Chrome下的Session Buddy和Tab Snooze好用，但是解决关键问题也够了。&lt;/p&gt;</description></item><item><title>广告过滤工具AdBlock、Adblock Plus和uBlock的简单对比</title><link>http://0x3f.org/posts/a-simple-comparison-among-adblock-ublock-and-adblock-plus/</link><pubDate>Sun, 01 Apr 2018 22:47:47 +0000</pubDate><guid>http://0x3f.org/posts/a-simple-comparison-among-adblock-ublock-and-adblock-plus/</guid><description>&lt;p&gt;Adblock Plus作者的那篇博客可能会影响很多人。我并不关心那些情怀的东西，只看疗效。&lt;/p&gt;
&lt;p&gt;简单地对比了下AdBlock、Adblock Plus、uBlock在Safari for Mac上的效果，所有样本和环境均为当前最新版本。AdBlock开启Safari内容过滤后是最好的，成功地过滤掉了我常访问的一个BT下载网站上的所有广告，而不开启Safari内容过滤时，会出现部分广告先显示后隐藏的情况。uBlock漏掉了个别不容易屏蔽的。而Adblock Plus最差，缺省设置下一条都没过滤掉，在选择更多的过滤规则后才过滤掉一部分。由于样本很单一，本结论不具有普适性。&lt;/p&gt;
&lt;p&gt;说句题外话，我觉得Adblock Plus这名字起得动机就挺不纯的，没有详细考证过，印象中这个东西是比AdBlock后出现的，而且这名字很容易让人理解成AdBlock的加强版。&lt;/p&gt;</description></item><item><title>变形金刚真人电影系列被重置</title><link>http://0x3f.org/posts/transformers-live-action-movie-series-reset/</link><pubDate>Sun, 18 Feb 2018 11:51:13 +0000</pubDate><guid>http://0x3f.org/posts/transformers-live-action-movie-series-reset/</guid><description>&lt;p&gt;根据这条&lt;a href="http://news.tfw2005.com/2018/02/16/transformers-cinematic-universe-current-movie-series-rebooted-358641"&gt;消息&lt;/a&gt;，变形金刚真人电影系列将会被新团队重置，原定在明年的第6部被取消。也就是说，看完今年大黄蜂的电影后，2021年前都不会有变形金刚主题的新片了。&lt;/p&gt;
&lt;p&gt;这种壮士断腕的做法多少算是个好消息吧，经历了变5的失败，再让麦克尔贝这么折腾下去，变形金刚这个IP就完蛋了。&lt;/p&gt;
&lt;p&gt;我对这件事是无可无不可的。作为一个八零后，我对变形金刚的情怀来自G1动画，所以我的关注点主要是还原G1动画风格的Master Piece系列。在MPM-3出来之前，我对电影系的玩具没多大兴趣。&lt;/p&gt;
&lt;p&gt;当年变1上映的时候，我很难认同电影系的风格。但是后来从变1到变3，也逐渐地开始接受它，毕竟随著技术的进步，审美风格也会发生变化，没必要固守二、三十年前的东西。我对电影系最大的意见是剧情太烂，有句话很对，说一部戏好不好关键看反派角色，《蝙蝠侠之黑暗骑士崛起》之所以口碑不错，主要是大反派小丑这个角色很立体。回头说当年的G1动画最成功的一点也是霸天虎尤其威震天这个角色塑造得比较成功。反观电影系，相对于汽车人华丽的人形态和隐藏形态，霸天虎阵营就是一群猥琐的低级生物，而且人物性格的塑造极其脸谱化。&lt;/p&gt;
&lt;p&gt;直到后来变4的时候，风格进一步变化，加入大量骑士元素，机械元素的减少导致科技感进一步下降。最要命的是变4的玩具做得实在是一塌糊涂。至于变5，那真是电影做得和玩具一样烂。&lt;/p&gt;
&lt;p&gt;真是成也麦克尔贝，败也麦克尔贝。&lt;/p&gt;</description></item><item><title>iQunix F60使用感受</title><link>http://0x3f.org/posts/iqunix-f60/</link><pubDate>Sat, 17 Feb 2018 15:40:47 +0000</pubDate><guid>http://0x3f.org/posts/iqunix-f60/</guid><description>&lt;p&gt;&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvx01vj5ej31kw0w04qq.jpg" alt="fullsizeoutput_392"&gt;&lt;/p&gt;
&lt;p&gt;我不喜欢冗余的东西。如果桌子足够大，我能接受的极限是87键。然而我的Filco 87圣手二代黑茶已经吃灰很久了，之前的主力是Poker II白青。所以目前主要的关注点还是在60键上。&lt;/p&gt;
&lt;p&gt;我对Poker整体上还是比较满意的，尤其是按键编程的功能很方便。但是有两点让我很不满意。一是做工一般，键帽的活动幅度较大，远远没有Filco的扎实感。二是不支持蓝牙，无线化是一个用了就回不去的东西。&lt;/p&gt;
&lt;p&gt;iQunix F60就是这么个东西，符合我对键盘所有的核心需求：支持蓝牙、做工好、60%布局、Cherry轴、PBT键帽。用了一段时间，整体是满意的。&lt;/p&gt;
&lt;p&gt;买的银白色，收到的是侧刻，算是个小惊喜吧，虽然不如无刻骚气，至少不像正刻那么平庸。铝合金外框加白色PBT键帽的颜值很高，整体很有质感。&lt;/p&gt;
&lt;p&gt;做工比Poker好很多，找回了Filco的扎实感。PBT的键帽不打油，这一点超过了Filco。&lt;/p&gt;
&lt;p&gt;续航一般，轻度使用可以持续一周。信号强度也很一般，一米的距离，已能感受到明显的延迟。不过这些在实际的使用中不是什么大问题。&lt;/p&gt;
&lt;p&gt;功能上，不支持键盘编程，这点不如Poker。但是可以用组合键交换左侧WIN键和ALT键，对Mac很友好。代替方向键的组合键位也比Poker合理。此外，可以用组合键切换有线和无线模式，支持在3台设备之间切换。&lt;/p&gt;</description></item><item><title>中国移动异地补卡记</title><link>http://0x3f.org/posts/story-of-changing-sim-card/</link><pubDate>Fri, 16 Feb 2018 17:24:59 +0000</pubDate><guid>http://0x3f.org/posts/story-of-changing-sim-card/</guid><description>&lt;p&gt;我妈的老SIM卡不能用在iPhone里。因为我的卡就是从大卡剪过来的，所以骑车转了一大圈，临近年关，大部分修手机的店、合作营业厅都关了，最后一个卖手机的店里的老板说这种老卡不能剪，只能换卡。&lt;/p&gt;
&lt;p&gt;之前听附近移动营业厅里的大堂经理说，换卡需要机主本人、身份证和服务密码，而且异地补卡只能去部分较大的营业厅。这个可以在网上营业厅里查到。&lt;/p&gt;
&lt;p&gt;事先在网上营业厅重置了服务密码。第二天一早，去了最近的可以异地补卡的营业厅。工作人员给了张纸条，让写下手机号、服务密码，他们查了一下，说是鉴权失败，让第二天再去。留了营业厅的电话，事先让他们查一下，确认可以办了再去。&lt;/p&gt;
&lt;p&gt;第三天早上十点，打电话过去，说是办异地补卡的人还没来。十一点再打过去，查了一下，说是可以办了。去之前差点没带手机，因为感觉就是办张卡，回来装也一样。事实证明，不带会后悔。&lt;/p&gt;
&lt;p&gt;补卡也需要用手写板签字和人脸识别，因为是2d图像识别，所以很傻，需要摇头、点头、眨眼、张嘴，在张嘴这一步重试了很多次都失败……&lt;/p&gt;
&lt;p&gt;补的第一张卡插到手机里不能识别，第二张才成功。&lt;/p&gt;
&lt;p&gt;总结以上，异地补卡需要注意这些点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本人、身份证、服务密码（服务密码可以去网上营业厅重置，前提是卡还在，还能接到短信）&lt;/li&gt;
&lt;li&gt;去能办理异地补卡的营业厅（可以在网上营业厅查询，或者打客服电话）&lt;/li&gt;
&lt;li&gt;不要去太早，最好事先打电话让他们查一下，确认可以办了再去&lt;/li&gt;
&lt;li&gt;一定要带手机和开卡槽的工具，现场装卡测试&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>飞利浦电动牙刷HX9903/42使用感受</title><link>http://0x3f.org/posts/philips-hx9903-42/</link><pubDate>Sat, 10 Feb 2018 17:23:15 +0000</pubDate><guid>http://0x3f.org/posts/philips-hx9903-42/</guid><description>&lt;p&gt;效果虽说没别人说的夸张，也的确刷得很干净，再就是缓解了胳膊的疲劳感。&lt;/p&gt;
&lt;p&gt;有个问题。刚开始的几天，虽然电池已经充满，但是震动强度很一般，而且手柄底部的压力警示灯一直闪，试过拔掉刷头，问题还在，说明是手柄的问题。直到提示电量紧张后第二次充电，之后才恢复正常。&lt;/p&gt;
&lt;p&gt;App、多种刷头、多种模式、压力警示和三级震动强度都是噱头，刷个牙而已，HX6730足够了，多交的几百块钱除了智商税，也就颜值和无线充电有点价值了。&lt;/p&gt;
&lt;p&gt;电动牙刷不是个用了就回不去的东西，不过体验确实很好，刷牙不再是例行公事和负担，而是件挺有意思的事。&lt;/p&gt;</description></item><item><title>用OTP Auth替换了Authy</title><link>http://0x3f.org/posts/migrate-from-authy-to-otp-auth/</link><pubDate>Tue, 06 Feb 2018 22:53:40 +0000</pubDate><guid>http://0x3f.org/posts/migrate-from-authy-to-otp-auth/</guid><description>&lt;p&gt;Authy的界面很花哨，但并不实用，管理多个两步验证账号时查询效率很低。OTP Auth采用更直观的列表布局，并且支持搜索，在用户体验和效率上有更大的优势。两者之间没有批量迁移数据的方式，只能逐个手动添加，很麻烦。&lt;/p&gt;</description></item><item><title>对XSS的防御更适合放在前端</title><link>http://0x3f.org/posts/better-to-do-defenses-against-xss-in-front-end/</link><pubDate>Tue, 06 Feb 2018 15:13:17 +0000</pubDate><guid>http://0x3f.org/posts/better-to-do-defenses-against-xss-in-front-end/</guid><description>&lt;p&gt;很多项目会把转义操作放在后端接口获取参数的地方，从而忽略了这样一个问题——为什么主流框架都不在获取参数的方法里实现这一点？&lt;/p&gt;
&lt;p&gt;以Laravel为例，如果可以这样获取转义后的参数：&lt;code&gt;$request-&amp;gt;escape('content')&lt;/code&gt;，代码会显得更优雅，而实际上只能用自己封装的函数手工转义：&lt;code&gt;my_escape($request-&amp;gt;get('content'))&lt;/code&gt;，很丑陋的代码。&lt;/p&gt;
&lt;p&gt;事实上，主流框架并非没有提供防御XSS的封装，只是都放在模板引擎里。这样做的依据是，XSS的原理是在原本用于展示的数据里包含了可执行的文本，但不是所有展示的位置都不应该包含可执行的文本。从另一角度上说，后端应该校验前端传递的数据，但不应该篡改它。&lt;/p&gt;</description></item><item><title>癸丑望，月有食之</title><link>http://0x3f.org/posts/lunar-eclipse/</link><pubDate>Wed, 31 Jan 2018 23:54:41 +0000</pubDate><guid>http://0x3f.org/posts/lunar-eclipse/</guid><description>&lt;p&gt;大概这是我第一次看月全食，暗红色，挺大个儿，但是拍出来就显得很小。论效果， iPhone X 还不如几年前的 LX5 。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230825113218000-5f7b2660efa35f1e658f5264fb3a9f14.avif" alt="2023-08-25-11-32-18-E9217241-82D8-4B12-8327-48DC8D947709_1_105_c"&gt;&lt;/p&gt;</description></item><item><title>解决Laravel的Facade在被Mock时不自动注入依赖的一种方法</title><link>http://0x3f.org/posts/manual-dependency-injection-with-laravel/</link><pubDate>Tue, 30 Jan 2018 15:41:16 +0000</pubDate><guid>http://0x3f.org/posts/manual-dependency-injection-with-laravel/</guid><description>&lt;p&gt;由于集成了Mockery，Laravel的Facade对单元测试非常友好，只需要一行代码就能实现mocking。&lt;/p&gt;
&lt;p&gt;例如，测试目标方法中调用了订单工具类的一个方法，在使用依赖注入的方式时，需要用三行代码实现对这个方法的mocking：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$fakeOrderTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;\App\Tool\Order&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$fakeOrderTool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;getById&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fakeOrder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;\App\Tool\Order&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$fakeOrderTool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;而用Facade是这样的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;OrderFacade&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;getById&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fakeOrder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当测试目标方法也属于订单工具类时，需要部分mock这个类，所以还要加上一行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;OrderFacade&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;makePartial&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但如果订单工具类的构造方法里有需要注入的依赖关系，这里并不会被执行。所以我在工具类基类里封装了一个方法，用反射机制实现手工注入依赖关系：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 注入依赖，用于单元测试
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @author donieli
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @version 5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;injectDependencies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$reflector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;\ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflector&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getConstructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getParameters&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$params&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$paramClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paramClass&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;\Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Dependency named &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; cannot be injected.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$paramClass&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call_user_func_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__construct&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后就可以这样处理：&lt;/p&gt;</description></item><item><title>从Vultr新加坡迁移到洛杉矶</title><link>http://0x3f.org/posts/migrate-vultr-from-singapore-to-los-angeles/</link><pubDate>Sun, 28 Jan 2018 14:15:57 +0000</pubDate><guid>http://0x3f.org/posts/migrate-vultr-from-singapore-to-los-angeles/</guid><description>&lt;p&gt;Vultr新加坡节点挂了两天了，不能翻墙简直什么都干不了。早上用CloudSpeed看了下，洛杉矶机房的响应速度还不错，就迁移了过去。&lt;/p&gt;
&lt;h2 id="shadowsocksr"&gt;ShadowsocksR&lt;/h2&gt;
&lt;p&gt;这个很简单，用&lt;a href="https://github.com/91yun/shadowsocks_install"&gt;一键安装脚本&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="网络加速"&gt;网络加速&lt;/h2&gt;
&lt;p&gt;用BBR，&lt;a href="https://teddysun.com/489.html"&gt;一键安装脚本&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="tiny-tiny-rss"&gt;Tiny Tiny RSS&lt;/h2&gt;
&lt;p&gt;先按照之前的&lt;a href="http://0x3f.org/post/ttrss/"&gt;笔记&lt;/a&gt;安装ttrss。&lt;/p&gt;
&lt;p&gt;然后重建一个空的ttrss的数据库：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; f6d92ad8efba /usr/bin/psql -c &lt;span class="s2"&gt;&amp;#34;drop database ttrss&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; f6d92ad8efba /usr/bin/psql -c &lt;span class="s2"&gt;&amp;#34;create database ttrss&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;把数据库的备份复制到容器里并导入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker cp ttrss.sql f6d92ad8efba:/tmp/ttrss.sql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; f6d92ad8efba /usr/bin/psql -d ttrss -f /tmp/ttrss.sql postgres
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;以root身份登录容器并删除备份文件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it --user root f6d92ad8efba /bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm /tmp/ttrss.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Unlox：兼顾安全和体验的东西深得我心</title><link>http://0x3f.org/posts/unlox/</link><pubDate>Sun, 14 Jan 2018 16:52:11 +0000</pubDate><guid>http://0x3f.org/posts/unlox/</guid><description>&lt;p&gt;买了Unlox。早就知道MacID，阴差阳错一直没买，所以这又是一次后知后觉的行为。&lt;/p&gt;
&lt;p&gt;曾经用过一段时间ControlPlane，通过多种条件自动判断场景以启用或关闭锁屏密码。后来在一次系统升级之后就不能用了。因为这个东西本身体验也不是很好，免费的东西折腾起来太耗费精力，所以付费买体验也是个不错的选择。&lt;/p&gt;
&lt;p&gt;有三个功能对我来说很有用。&lt;/p&gt;
&lt;p&gt;首先是用Face ID解锁Mac。在Mac被唤醒后，iPhone X自动弹出解锁的通知，点击后Unlox被打开并自动调用Face ID，验证通过后Mac即被解锁。不过两次Face ID验证稍显繁琐，如果在iPhone锁屏界面验证通过后就自动解锁，体验会更好。不过我猜应该是iOS在这个地方不会通知到App。&lt;/p&gt;
&lt;p&gt;其次是Tap解锁。用手指点击触摸板，点击次数和每次用的手指数目可以自定义。这个方式确实很方便。为了加强安全性，还可以设置当手机断开时禁用Tap解锁。&lt;/p&gt;
&lt;p&gt;第三是离开时自动锁屏。可以设置当手机和Mac之间的蓝牙连接信号减弱多少时自动锁屏。虽然对于Macbook用处不大，也不失为忘记合上屏幕时的一种补救手段。&lt;/p&gt;
&lt;p&gt;此外还有其它一些功能，例如通过手机锁定或解锁Mac、靠近时自动唤醒Mac等。&lt;/p&gt;
&lt;p&gt;今年Apple应该会全系支持Face ID，所以这只是一个过渡方案。&lt;/p&gt;</description></item><item><title>密码管理的最佳实践</title><link>http://0x3f.org/posts/the-best-practice-of-password-management/</link><pubDate>Wed, 27 Dec 2017 17:26:17 +0000</pubDate><guid>http://0x3f.org/posts/the-best-practice-of-password-management/</guid><description>&lt;p&gt;通密之所以不应该被过分指责，是因为有其存在的道理，没有哪种方案的管理成本比它更低，它不需要购买昂贵的1password，不需要担心临时用的时候突然想不起来，而且，只要这个密码足够强壮并且使用环境足够安全，大多数情况下也不会有什么问题。通密的问题在于它的风险成本太高，一旦一处泄漏，所有使用这个密码的地方都不安全。&lt;/p&gt;
&lt;p&gt;另一个极端是，使用很复杂的密码，每个账号都不同，甚至用密码生成工具生成完全没有规律的随机字符串。这种方案的安全性很高，高到连你自己都记不住。&lt;/p&gt;
&lt;p&gt;所以我需要这样一套好的方案，它应该在安全性和易用性之间取得一个比较好的平衡，并且随著方法论和工具链的进化，这个平衡可以无限逼近黄金分割点。&lt;/p&gt;
&lt;p&gt;首先，密码应该是复杂但容易记住的。密码的复杂度和记忆负担并不成正比，例如如果你实在记不住“ppnn13%,dkstFeb1st”，那么这样呢——“娉娉袅袅十三余，豆蔻梢头二月初”。密码只是一个字符串，如果不去死记最终的值，而是字符串背后的规律，记忆的压力就会小很多。&lt;/p&gt;
&lt;p&gt;但考虑到每个账号都想一个这样的密码是不现实的，而且怎么解决记忆密码和账号的对应关系的问题？所以进一步，可以用这样的密码当前缀，每个密码的前缀都一样，然后针对每个账号创造一个后缀，这个后缀应该是每个账号都不同的，且和账号有某种只有你自己才知道的关联，这样你可以随时根据账号计算出它的后缀。例如，可以用账号拼音首字母（&lt;em&gt;当然，实际的规则应该更复杂一点&lt;/em&gt;）。&lt;/p&gt;
&lt;p&gt;这样你就有了足够复杂、每个账号都不同并且很容易记住的密码。进一步地，在私有设备上可以利用文本替换功能（&lt;em&gt;例如：Alfred for Mac的Snippets功能&lt;/em&gt;）快速输入通用前缀，某些支持按键编程的机械键盘会有更好的体验。&lt;/p&gt;
&lt;p&gt;不过好记性不如烂笔头，为防万一，还是需要一个Plan B。主流的密码管理工具主要有这么几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器的账号记忆功能&lt;/li&gt;
&lt;li&gt;操作系统的keychain&lt;/li&gt;
&lt;li&gt;在线密码管理工具&lt;/li&gt;
&lt;li&gt;离线密码管理工具&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;浏览器一般是把密码以明文存储在本地的，firefox虽然有个主密码，但只是个幌子，别人仍然可以拿到它记录密码的数据库文件。这种做法的逻辑在于，设备上存储的数据的安全性由操作系统和用户负责，换句话说，用户不应该允许他人用自己的权限登录设备。但实际上很难避免这种情况，而且还要考虑到系统被入侵的可能。所以，只应该让浏览器记住那些最不重要的账号。&lt;/p&gt;
&lt;p&gt;相对来说，操作系统的keychain一般有自动锁定的功能，会更安全一些。但是仍无法完全避免上述问题。而且keychain只能记录账号和密码，无法存储更多的附加信息。所以这种工具也只应该存储一些不重要的账号。&lt;/p&gt;
&lt;p&gt;最著名的在线密码管理工具应该是Lastpass。关于它的安全性有很多种说法，不过我觉得但凡是敏感数据都不要存储到线上，所以这种方式不予考虑。&lt;/p&gt;
&lt;p&gt;我倾向于使用离线的密码管理工具。1password据说很好用，但是太贵了，而且开源免费的keepass已经完全够用了。我在Mac上用KeePassXC，在iOS中用MiniKeePass，私钥文件离线存储，然后数据库文件用Dropbox同步就可以了。&lt;/p&gt;
&lt;p&gt;此外，对于重要的账号，如果支持两步验证，一定要开启，然后用OTP Auth管理即可。&lt;/p&gt;
&lt;p&gt;最终的方案是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方法论：统一的复杂但有规律的前缀+根据账号计算出来的后缀&lt;/li&gt;
&lt;li&gt;工具链：KeePass + OTP Auth + Dropbox&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Laravel单元测试错误：1205 Lock wait timeout exceeded</title><link>http://0x3f.org/posts/1205-lock-wait-timeout-exceeded/</link><pubDate>Fri, 22 Dec 2017 15:47:32 +0000</pubDate><guid>http://0x3f.org/posts/1205-lock-wait-timeout-exceeded/</guid><description>&lt;p&gt;错误信息：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1205 Lock wait timeout exceeded; try restarting transaction&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原因之一是测试用例里重写的tearDown()方法中没有调用父类的该方法。因为DatabaseTransaction这个trait自动开启了事务，对应的回滚方法在测试用例基类的tearDown()中执行。&lt;/p&gt;</description></item><item><title>用Charles拦截iOS APP HTTPS请求</title><link>http://0x3f.org/posts/ios-app-intercepting-using-charles/</link><pubDate>Fri, 22 Dec 2017 15:17:04 +0000</pubDate><guid>http://0x3f.org/posts/ios-app-intercepting-using-charles/</guid><description>&lt;h2 id="实践环境"&gt;实践环境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Charles 4.2&lt;/li&gt;
&lt;li&gt;iOS 11.2.1&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安装证书"&gt;安装证书&lt;/h2&gt;
&lt;p&gt;按照Charles菜单（Help -&amp;gt; SSL Proxying -&amp;gt; Install Charles Root Certificate on a Mobile Device or Remote Browser）的指示，设置iOS的系统代理。&lt;/p&gt;
&lt;p&gt;为了以后使用方便，可以在代理工具（如ShadowRocket）里设置，注意使用时应配置代理工具对全部流量使用代理，如果使用PAC之类动态代理可能会拦截不到。&lt;/p&gt;
&lt;p&gt;在iOS的Safari中访问上面提示中的网址，会弹出提示安装证书。iOS 10.3以后还要设置信任该证书（设置-&amp;gt;通用-&amp;gt;关于本机-&amp;gt;证书信任设置）。&lt;/p&gt;
&lt;h2 id="配置charles拦截https请求"&gt;配置Charles拦截HTTPS请求&lt;/h2&gt;
&lt;p&gt;路径为：Proxy -&amp;gt; SSL Proxying Settings&lt;/p&gt;
&lt;p&gt;可以设置对特定的主机名和端口拦截，也可以直接保存，此时对所有请求均会拦截。&lt;/p&gt;
&lt;h2 id="拦截"&gt;拦截&lt;/h2&gt;
&lt;p&gt;iOS中打开上述代理，APP中发送的请求就会在Charles里列出来。&lt;/p&gt;</description></item><item><title>测试驱动开发的实际收益</title><link>http://0x3f.org/posts/the-real-income-of-tdd/</link><pubDate>Sun, 17 Dec 2017 14:20:02 +0000</pubDate><guid>http://0x3f.org/posts/the-real-income-of-tdd/</guid><description>&lt;p&gt;我并不试图系统地谈TDD，因为我在这方面的经验还不足以做到这一点。但是TDD的一些方法论和工具确实解决了我在实际开发过程中遇到的一些问题。&lt;/p&gt;
&lt;p&gt;第一个问题是健壮性。尤其是对于我这样思维发散、容易迷失又喜欢重构的人，TDD给了我一个明确的目标，在一切刚开始的时候，我要做的只是满足测试用例，让它们由红变绿。到了重构阶段，我就可以把精力放到优化代码上面，且不必对健壮性有过多的担心。在此之前，由于手动测试比较麻烦，很多时候惰性会说服潜意识告诉自己这部分逻辑很简单、不会有什么bug，结果提交测试后却一再地发生问题。&lt;/p&gt;
&lt;p&gt;第二个问题是效率。曾经只有不忙的时候才会写测试用例，但是现在一般都会写，因为确实可以提高开发效率，而不只是保证重构的健壮性。可能对于所有对单元测试不熟悉的人来说，这都是匪夷所思的，我也曾认为单元测试只是用来保证健壮性的，必然和开发效率是一对矛盾，因为要花很多时间写测试代码。这种想法首先是因为对单元测试不熟悉，所以才需要花很多时间在上面。其次是没有看到它所带来的好处。&lt;/p&gt;
&lt;p&gt;例如你要实现一整套退款单的功能，退款单是依赖订单的，这意味著你需要不只一条符合条件的订单数据。但是订单是有状态的，随著时间的推移、人为的操作或者开发过程中程序的影响，状态会变得不再符合你的要求，这时候你就必须停下来去做更多符合要求的订单。而创建订单也存在很多麻烦，你需要找到有库存的商品，有时候还要去库管系统中补充库存，然后下单并支付。最后花了很多时间做出来的订单，因为正在开发的退款单的程序出现的一个小问题变得不能使用！时间被大量浪费在创建所依赖的上游数据上。&lt;/p&gt;
&lt;p&gt;这时候如果用单元测试并mock出依赖关系，就可以随时随地、无限制地执行相关的业务逻辑。对效率的提高不言而喻。&lt;/p&gt;
&lt;p&gt;特别的，mock并不是随时可以抓起的救命稻草，它的原罪在于：不负责任地滥用mock会导致很多问题被掩盖。因此，对mock的使用应该是节制的、目标明确的。&lt;/p&gt;
&lt;p&gt;当然，这并不包括单纯地为了提高代码覆盖率而使用mock，只所以这是个在很多强制TDD的团队里的普遍现象，归根结底是因为KPI是万恶之源，任何好的方法论，一旦沦为KPI，就离死不远了。&lt;/p&gt;</description></item><item><title>BaiduPCS：当前最好用的百度网盘下载工具</title><link>http://0x3f.org/posts/baidupcs/</link><pubDate>Tue, 12 Dec 2017 21:21:16 +0000</pubDate><guid>http://0x3f.org/posts/baidupcs/</guid><description>&lt;p&gt;BaiduPCS是个命令行工具，用于下载百度网盘中的资源。之前用的是浏览器插件，需要先创建分享，再拿到下载链接，最后用下载工具下载。这个工具可以直接执行一条命令下载指定的资源，非常方便。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/GangZhuo/BaiduPCS/blob/master/README.md"&gt;这里&lt;/a&gt;有安装说明，然后按照&lt;a href="https://github.com/GangZhuo/BaiduPCS/wiki/BaiduPCS-%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"&gt;使用说明&lt;/a&gt;操作即可。&lt;/p&gt;</description></item><item><title>iOS垃圾短信过滤器：熊猫吃短信</title><link>http://0x3f.org/posts/panda-eats-sms/</link><pubDate>Sun, 10 Dec 2017 12:08:47 +0000</pubDate><guid>http://0x3f.org/posts/panda-eats-sms/</guid><description>&lt;p&gt;“熊猫吃短信”是个新上架的App，用于过滤垃圾短信。据说是基于机器学习训练出来的，用了一周，识别得非常准确。&lt;/p&gt;
&lt;p&gt;之前用的腾讯手机管家，即使把“精准识别”、“上传到云端”等选项都打开，还会有漏网之鱼，而且会牺牲隐私。这个App声称不会主动上传短信。最重要的是，这一周里所有不关心的短信都被过滤掉了，而且没有失误。&lt;/p&gt;</description></item><item><title>全新Kindle Oasis使用感受</title><link>http://0x3f.org/posts/the-all-new-kindle-oasis/</link><pubDate>Sat, 09 Dec 2017 14:03:08 +0000</pubDate><guid>http://0x3f.org/posts/the-all-new-kindle-oasis/</guid><description>&lt;p&gt;&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvwzr2sbyj31kw1kwe83.jpg" alt="fullsizeoutput_358"&gt;&lt;/p&gt;
&lt;p&gt;早在Paperwhite 1的时候我就不喜欢它的工业设计：边框太宽，屏幕内陷。此外，非人体工学设计和没有实体翻页键导致单手握持体验很差。再有就是做工的问题，机身表面接缝处缝隙明显而不均匀、通体强烈的塑料感。然而还是从一代用到了三代，除了kpw是kindle全系列里性价比最高的产品线之外，还有就是没有其它任何一款产品解决了kpw的主要问题。&lt;/p&gt;
&lt;p&gt;例如Voage，虽然屏幕不内陷了、楔形机身优化了握持感、增加了翻页键，但整体的设计只算是在kpw基础上的优化，何况各项硬件配置和kpw3几乎无差。&lt;/p&gt;
&lt;p&gt;后来当第一代Oasis发布的时候，看了第一眼就瞬间失掉了兴趣。捆绑的充电保护壳绝对是体验杀手，装上壳比kpw还要厚重，不装的话本体的续航又很差，频繁拆装也很不方便，这样的体验连kpw都不如。所以我很不看好它，果然很快在今年六月就下架了。&lt;/p&gt;
&lt;p&gt;十月刚看到新Oasis的消息时，马上觉得这回终于有买的价值了。&lt;/p&gt;
&lt;p&gt;首先是7寸的屏幕，瞬间和其它产品线拉开了距离。更大的屏幕意味著能展示更多内容，增加了宽度后也更接近实体书的观感。&lt;/p&gt;
&lt;p&gt;工业设计相对于我的kpw3当然是有了质的改变。玻璃材质的纯平表面，金属背壳，没有了kpw的塑料感，显得更精致。得益于窄边框，7寸屏的机身长度比6寸的kpw还短。虽然因为加宽了屏幕和增加了单手握持的边框导致机身宽度超过kpw很多，不过在平时携带中并没有造成很多困扰。&lt;/p&gt;
&lt;p&gt;单手握持是ko系列的主要卖点，实际使用体验当然很好。为握持设计的宽边框加上实体翻页键非常方便。虽然因为加大屏幕和增加续航导致194g的重量远远超过1代的131g，但还是比kpw轻了10g，而且主要重量集中在单手握持的一边，杠杆效应很小。配合重力感应，随时换手可以有效缓解疲劳。当然，作为长时间单手握持的阅读设备，重量自然越轻越好，这一点上，ko还有很大优化的空间。&lt;/p&gt;
&lt;p&gt;此外，新ko的做工远远好于kpw，没有了廉价感。12颗背光灯使得背光的均匀度比kpw强了很多，几乎不会有kpw上明显的光影。性能上是现在kindle全系列里最高的，翻页时虽然还会看到闪屏，但比以前已经快了很多。自动亮度调节算是个聊胜于无的功能吧。至于防水和有声书，我没有这方面的需求。&lt;/p&gt;
&lt;p&gt;如果说缺点的话，还是续航。虽然相对于1代本体，续航已经达到可用的水平，但是对于被其它产品线惯坏的我们来说，新ko电量的消耗还是快了点。我没有精确的对比，但是能明显地感觉到比kpw掉得快不少。&lt;/p&gt;</description></item><item><title>清洁手机的最佳实践</title><link>http://0x3f.org/posts/how-to-clean-a-phone/</link><pubDate>Sun, 03 Dec 2017 22:51:42 +0000</pubDate><guid>http://0x3f.org/posts/how-to-clean-a-phone/</guid><description>&lt;p&gt;以前的做法是先用湿巾清理，再用纸巾擦干。后来屏幕的触感逐渐不如开始时顺滑，也更容易沾指纹和灰尘，而且不容易清除。估计应该是湿巾的酒精会腐蚀屏幕的涂层，纸巾粗糙的表面也会造成磨损。&lt;/p&gt;
&lt;p&gt;现在先用软毛刷扫除灰尘，然后用3M魔布擦拭。效果应该会更好。&lt;/p&gt;</description></item><item><title>Firefox Quantum：狐狸的反击</title><link>http://0x3f.org/posts/firefox-quantum/</link><pubDate>Sun, 03 Dec 2017 21:53:18 +0000</pubDate><guid>http://0x3f.org/posts/firefox-quantum/</guid><description>&lt;p&gt;不知不觉已经很多年没有用过Firefox了。在Chrome发布之前，这只狐狸以一己之力扛著互联网承前启后的大旗。后来被Chrome在网页加载速度上吊打，逐渐式微。之后还在用Firefox的人一般也只是因为受不了Chrome的内存占用。&lt;/p&gt;
&lt;p&gt;Firefox Quantum刚发布的时候我就安装了，以为是个全新的项目，新项目初期往往特性不健全，所以就没有太多关注。&lt;/p&gt;
&lt;p&gt;然后发现版本号接续了旧版，也兼容原Firefox的插件，所以就装上几个必要的插件，尝试了一下。新的UI借鉴了Chrome，不像原来那么过时。最重要的是内存占用和网页打开速度比Chrome有优势。如官方宣传语所说——快而不俗。&lt;/p&gt;
&lt;p&gt;准备把默认浏览器改成FQ，用一段时间看看。&lt;/p&gt;</description></item><item><title>Vim最好的PHP语法高亮插件</title><link>http://0x3f.org/posts/the-best-php-syntax-file-of-vim/</link><pubDate>Tue, 28 Nov 2017 15:55:59 +0000</pubDate><guid>http://0x3f.org/posts/the-best-php-syntax-file-of-vim/</guid><description>&lt;p&gt;&lt;a href="https://github.com/StanAngeloff/php.vim"&gt;StanAngeloff/php.vim&lt;/a&gt;应该是目前最新、最全的PHP语法高亮插件了，它解决了旧版本无法高亮&lt;code&gt;@throws&lt;/code&gt;的问题。&lt;/p&gt;
&lt;p&gt;默认会把方法注释全部当做普通注释显示，也就是没有高亮，需要专门做配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;PhpSyntaxOverride&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="nx"&gt;phpDocTags&lt;/span&gt; &lt;span class="nx"&gt;phpDefine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="nx"&gt;phpDocParam&lt;/span&gt; &lt;span class="nx"&gt;phpType&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;augroup&lt;/span&gt; &lt;span class="nx"&gt;phpSyntaxOverride&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;autocmd&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;PhpSyntaxOverride&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;augroup&lt;/span&gt; &lt;span class="nx"&gt;END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>iPhone X官方硅胶保护壳使用感受</title><link>http://0x3f.org/posts/iphone-x-silicone-case/</link><pubDate>Sun, 26 Nov 2017 12:50:13 +0000</pubDate><guid>http://0x3f.org/posts/iphone-x-silicone-case/</guid><description>&lt;p&gt;我相信所有注重体验的人都不愿意用保护壳，我也一样，所以用iPhone 6的两年多里绝大部分时间也都是裸奔。&lt;/p&gt;
&lt;p&gt;对于给X加壳这件事，我是很矛盾的，然而面对这个既易碎又碎不起的东西，贫穷限制了我对体验的偏执。&lt;/p&gt;
&lt;p&gt;对于壳的选择，我有这些考虑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;防护性好：毕竟这是加壳的唯一目的，所以那些超薄的壳就在考虑范围内了。&lt;/li&gt;
&lt;li&gt;易装卸：只有出门时会加壳，在家要去掉，所以这是个很频繁的行为，既要容易操作，又要不伤手机。&lt;/li&gt;
&lt;li&gt;易维护：方便清洁，所以皮质的就不考虑了。&lt;/li&gt;
&lt;li&gt;贴合度高，触感好：体验还是很重要，软壳一般很难做到这一点，所以范围限制在硬壳上。&lt;/li&gt;
&lt;li&gt;外观简约。&lt;/li&gt;
&lt;li&gt;材料安全。&lt;/li&gt;
&lt;li&gt;试错成本低：少花冤枉钱，节省时间精力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;符合这些条件的就只剩下官方硅胶壳了，然而我还是在颜色的选择上纠结了很长时间。因为硅胶壳容易粘灰，所以越是浅色越不明显，然而深色可以减少和X黑色前面板的割裂感。最终选择了钴蓝色。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvwz3j8r1j31kw16onpd.jpg" alt="IMG_0008"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvwzf3edsj31kw16oqv5.jpg" alt="IMG_0009"&gt;&lt;/p&gt;
&lt;p&gt;用了一周的时间，完全符合预期。&lt;/p&gt;</description></item><item><title>电影《疾速追杀》</title><link>http://0x3f.org/posts/movie-john-wick/</link><pubDate>Sun, 26 Nov 2017 10:09:34 +0000</pubDate><guid>http://0x3f.org/posts/movie-john-wick/</guid><description>&lt;p&gt;上周看了《疾速追杀》和《疾速特攻》，后者是前者的第二部。&lt;/p&gt;
&lt;p&gt;情节比较老套：一个因爱退隐的职业杀手，在妻子病逝、黑道欺凌下，不得以奋起反击、与整个杀手行业为敌，最后善恶有报、空余萧索。&lt;/p&gt;
&lt;p&gt;知道这部戏是因为和《极寒之城》是同一个导演，卖点都是暴力美学，风格不同。《极寒之城》用不加特效的长镜头表现格斗的残酷，画风冷峻。《疾速》系列更像《杀死比尔》，场面华丽，十步杀一人、千里不留行。&lt;/p&gt;
&lt;p&gt;关于暴力美学，维基百科是这么解释的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;主要在官感上，使暴力以美学的方式呈现，诗意的画面，甚至幻想中的镜头来表现人性暴力面和暴力行为。观赏者本身往往惊叹于艺术化的表现形式，无法对内容产生具体的不舒适感。支持人士往往称「暴力程度与票房收入成正比」，社会道德捍卫者和舆论谴责人士则称其是对社会道德教化的阻碍和负面影响；恐引发心理未臻成熟的人们，间接以为暴力行为亦是一种美感的呈现。&lt;/p&gt;
&lt;p&gt;在众多香港导演中，吴宇森是运用这种电影表现手法的代表性人物。其标志性的白鸽漫天飞舞，手持双枪的英雄人物纵横在屏幕之上，使象征和平和安详的白鸽与血腥暴力的枪弹形成了强烈的视觉反差，吸引了无数的目光。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然而我并不打算马上去看新《追捕》，炒冷饭的鲜有好戏，等等再说。&lt;/p&gt;</description></item><item><title>iPhone X使用感受</title><link>http://0x3f.org/posts/iphone-x/</link><pubDate>Sun, 12 Nov 2017 13:10:05 +0000</pubDate><guid>http://0x3f.org/posts/iphone-x/</guid><description>&lt;p&gt;上手用了两天，感觉优点多于缺点，总体是进步的。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvwxh8lvvj31kw16ohdv.jpg" alt="P1030587"&gt;&lt;/p&gt;
&lt;p&gt;如果没有新的工业设计，我可能会把小6继续用下去。毕竟当初就对小6的白带和粗边框很不满意，虽然8因为改回玻璃背板已经基本解决白带问题，但是前面板几乎没有变化，一个工业设计用了四代，再优秀也审美疲劳了，而且那个屏占比在现在的千元机里也是倒数了，哪怕把边框做得再窄一点，8也不至于跳水成现在这样。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvwxoqh8rj31kw16ohdv.jpg" alt="P1030579"&gt;&lt;/p&gt;
&lt;p&gt;买的银色，实际观感更接近乳白色，而深空灰更接近黑色。后者配色的一体性并没有别人说的那么好，而前者配色也没有很强的割裂感。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvwxy4xfyj31kw16ob2b.jpg" alt="P1030585"&gt;&lt;/p&gt;
&lt;p&gt;宽度比6稍大，长度更长，单手握持无压力，不过单手操作就别想了，即使是6，搭配指环单手操作也不方便。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvwy2ob4ej31kw16ob2b.jpg" alt="P1030584"&gt;&lt;/p&gt;
&lt;p&gt;前面板在息屏状态下一体性很好。当然我不认为这是个很重要的标准，好像罗永浩说过黑色边框可以隐藏低成本的做工，白色边框想做好更难，不管真假，息屏美学就是个营销手段，有谁会盯著息屏的手机瞅？&lt;/p&gt;
&lt;p&gt;功能方面，这次最大的卖点就是Face ID，体验真是比Touch ID好太多！尤其是我手汗多，指纹解锁失败率很高，不过这些年倒是因此养成了一天洗几十次手的习惯……&lt;/p&gt;
&lt;p&gt;性能上，找回了6在iOS8时的流畅度。如果没有意外，6在iOS11下就现在这德性了，追求流畅度的在10.3.3止步吧。&lt;/p&gt;
&lt;p&gt;拍照方面，「世界第二」的摄像头效果搭配人像模式效果比6好很多。&lt;/p&gt;
&lt;p&gt;至于续航，虽然免不了一天一充，起码比6在iOS11下强多了，毕竟多了一千毫安。&lt;/p&gt;
&lt;p&gt;此外，作为古老的小6的用户，3D Touch、抬手亮屏、随时喊Siri也有更好的体验。&lt;/p&gt;
&lt;p&gt;屏幕方面，全面屏+OLED效果拔群。看久了X的屏幕，再看6的会觉得模糊很多。另外，True Tone比起Night Shift也更智能了。&lt;/p&gt;
&lt;p&gt;异形屏不是苹果的首创，全面屏也不是小米的首创，而它们连同三星S8已然成了全面屏的三个流派。我个人更倾向于异形屏，虽然iPhone X的屏占比实际上并不是非常高，不过观感上更彻底。S8用曲面屏把左右边框做到视觉上宽度接近零，不过三星的供货问题是这个流派最大的障碍。至于小米MIX，完全就是在低成本、供应链和软件生态话语权弱、硬件技术落后等因素作用下、利用普通LCD面板追全面屏热度的怪胎。MIX1就是个半成品，到了MIX2才算基本可用。所以小米不是第一个做全面屏的，但是是第一个不要脸的，还是老罗实在，「全面屏」后面还加个「almost」。&lt;/p&gt;
&lt;p&gt;未来一两年，从千元机到高端机会全面普及全面屏。中低端机型主流应该会选择坚果Pro2的风格，用普通面板，然后尽量把边框做窄。高端机型在异型屏和曲面屏之间会有一场好戏。&lt;/p&gt;
&lt;p&gt;取消Home键换来的新的交互方式，整体上是进步了。回到主界面和切换任务这两个常用操作改用触摸手势，取消了到实体键的依赖，也提高了效率。侧边键得到了更充分的利用，呼出Siri和Apple Pay从Home键挪了过来。如果同时按侧边键+音量减能自定义或者实现像坚果Pro2闪念胶囊按键那样的功能会更好。&lt;/p&gt;
&lt;p&gt;缺点主要是边框和厚度，原本我对小6的厚度是很满意的，只是希望把边框做窄点。现在不但祖传的粗边还在，还越做越厚是什么毛病？！&lt;/p&gt;</description></item><item><title>电影《极寒之城》</title><link>http://0x3f.org/posts/movie-atomic-blonde/</link><pubDate>Sun, 29 Oct 2017 10:14:56 +0000</pubDate><guid>http://0x3f.org/posts/movie-atomic-blonde/</guid><description>&lt;p&gt;这是最近看的电影里让我印象最深的一部。&lt;/p&gt;
&lt;p&gt;故事背景是1989年柏林墙倒塌前发生在德国的一场谍战。剧情组织得很一般，冷战和谍战这两个卖点做得都不成功，虽然塞隆和波多拉两位女神的床戏挽救了一切，但是女同的卖点只是一道开胃菜，最精彩的部分是中后段的一场动作戏，塞隆单挑一群克格勃，同时还要保护一个东德叛谍，长达数分钟的一个长镜头，场面极为真实，一改一般好莱坞动作片里打不死的风格。&lt;/p&gt;</description></item><item><title>读完《谈美》</title><link>http://0x3f.org/posts/after-reading-tan-mei/</link><pubDate>Sun, 29 Oct 2017 09:21:58 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-tan-mei/</guid><description>&lt;p&gt;&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvwx0p3twj31kw1kwhdu.jpg" alt="fullsizeoutput_301"&gt;&lt;/p&gt;
&lt;p&gt;这本书讲的是「什么是美」。读完后对美有了一些基本的概念，才知道我的审美水平还停留在「以快感为美」的阶段。&lt;/p&gt;
&lt;p&gt;朱自清的序里的一些话说得很好：「新文化是「外国的影响」，自然不错；但说一般青年不留余地地鄙弃旧的文学艺术，却非真理。」、「许多青年腻味了，索性一切不管，只抱著一条道理，「有文艺的嗜好就可以谈文艺」。这是「以不了了之」，究竟「谈」不出什么来。」&lt;/p&gt;</description></item><item><title>用Tiny Tiny RSS搭建私人阅读器的步骤</title><link>http://0x3f.org/posts/ttrss/</link><pubDate>Fri, 27 Oct 2017 14:12:16 +0000</pubDate><guid>http://0x3f.org/posts/ttrss/</guid><description>&lt;h2 id="优势"&gt;优势&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;自定义过滤器&lt;/li&gt;
&lt;li&gt;全功能，无限制&lt;/li&gt;
&lt;li&gt;利用已有VPS，无需额外费用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;h3 id="安装并启动docker"&gt;安装并启动docker&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl https://get.docker.com/ &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// centos7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl start docker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="安装postgre"&gt;安装postgre&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d --name ttrssdb nornagon/postgres
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="安装tiny-tiny-rss"&gt;安装tiny tiny rss&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d --link ttrssdb:db -p 80:80 -e &lt;span class="nv"&gt;SELF_URL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://example.org/ttrss fischerman/docker-ttrss
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;example.org&lt;/code&gt;替换成VPS的IP或者对应的域名。&lt;/p&gt;
&lt;h2 id="配置"&gt;配置&lt;/h2&gt;
&lt;h3 id="配置主程序"&gt;配置主程序&lt;/h3&gt;
&lt;p&gt;访问&lt;code&gt;http://example.org/ttrss&lt;/code&gt;，用户名&lt;code&gt;admin&lt;/code&gt;，密码&lt;code&gt;password&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="伪装成fever"&gt;伪装成fever&lt;/h3&gt;
&lt;p&gt;如果RSS阅读器不支持ttrss，但支持fever，例如reeder，可以通过安装插件伪装成fever：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/rannen/tinytinyrss-fever-plugin.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker cp fever &lt;span class="o"&gt;[[&lt;/span&gt;CONTAINER ID&lt;span class="o"&gt;]]&lt;/span&gt;:/var/www/plugins
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后去设置见面启用fever插件，并在fever插件的配置栏设置单独的密码，该栏目中会显示在RSS阅读器中使用的接口地址，用户名就是&lt;code&gt;admin&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="备份"&gt;备份&lt;/h2&gt;
&lt;p&gt;每天凌晨3点备份数据库到dropbox。&lt;/p&gt;
&lt;h3 id="下载dropbox上传脚本"&gt;下载dropbox上传脚本&lt;/h3&gt;
&lt;p&gt;在VPS的&lt;code&gt;/root&lt;/code&gt;下执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://raw.github.com/andreafabrizi/Dropbox-Uploader/master/dropbox_uploader.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;执行命令并按提示操作：&lt;/p&gt;</description></item><item><title>过度优化和过度设计</title><link>http://0x3f.org/posts/talk-about-excessive-design/</link><pubDate>Sun, 22 Oct 2017 21:38:08 +0000</pubDate><guid>http://0x3f.org/posts/talk-about-excessive-design/</guid><description>&lt;p&gt;我见过两种程序员，一种是想做事的，一种是混饭吃的。&lt;/p&gt;
&lt;p&gt;第一种人最容易犯两个错误，一是过度优化，二是过度设计。两种错误共同的原因是经验不足，不同的地方是过度优化往往出于知其然不知其所以然，而过度设计一般是想得太远从而脱离实际。&lt;/p&gt;
&lt;p&gt;比如我见过的一个人，凡是联表的语句，都要拆开来写，完全不考虑这些联表语句实际会不会发生性能问题。**这就是过度优化，只记住一些成例和范式，不从实际出发，胶柱鼓瑟，刻舟求剑。**联表当然会造成数据量以笛卡尔积的形式增长，但如果所联表的数据量并不大，或者通过限制条件过滤后的数据量不大，并不会出现性能问题，而拆开SQL语句会导致代码量增大、可读性下降，是得不偿失的。&lt;/p&gt;
&lt;p&gt;至于过度设计，我自己就是个很好的反面教材。刚工作的时候，我在写程序之前和过程中会不断地冒出新的想法，设想到很多种可能，为了照顾到这些可能性，我会不断地重构程序，导致出活很慢。多数人并不会认真了解别人，只是从结果上武断地下结论。所以关于我写程序太慢的说法就悄悄流传开，而那些程序写得很烂、混饭吃但出活很快的人反而获利颇丰。最可笑的是过了很长时间后回顾曾经设想到的可能性，几乎全部没有发生。&lt;strong&gt;为一些将来可能发生而实际没有发生的可能性，在一开始就花费更多的成本，这就是过度设计。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不过经验作为知识存量，是不值钱的，假以时间，有一定认知水平、不甘于庸俗的人总可以积累得到。所以相对于第二种人，我宁愿和第一种共事。&lt;/p&gt;</description></item><item><title>搭好了SSR</title><link>http://0x3f.org/posts/ready-for-ssr/</link><pubDate>Wed, 18 Oct 2017 15:34:33 +0000</pubDate><guid>http://0x3f.org/posts/ready-for-ssr/</guid><description>&lt;p&gt;搭在vultr东京节点的SS在家里的网络上已经不能用了，lantern和大杀器也不稳定到基本没有可用性的程度。短短几天时间，三把梯子挂了仨。&lt;/p&gt;
&lt;p&gt;搭好了SSR，等着晚上回去测试。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SSR一键部署脚本：https://github.com/91yun/shadowsocks_install&lt;/li&gt;
&lt;li&gt;Mac的SSR客户端：https://github.com/qinyuhang/ShadowsocksX-NG-R/releases&lt;/li&gt;
&lt;li&gt;iOS的SSR客户端：ShadowRocket&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>用gv.vim查看git提交历史</title><link>http://0x3f.org/posts/gv-vim/</link><pubDate>Wed, 18 Oct 2017 13:28:16 +0000</pubDate><guid>http://0x3f.org/posts/gv-vim/</guid><description>&lt;p&gt;&lt;a href="https://github.com/junegunn/gv.vim"&gt;gv.vim&lt;/a&gt;是fugitive的插件，用于查看git提交历史，特点是速度快、好用。我现在用它做code review。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;gll&lt;/span&gt; :&lt;span class="nx"&gt;GV&lt;/span&gt; &lt;span class="p"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;merges&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;glc&lt;/span&gt; :&lt;span class="nx"&gt;GV&lt;/span&gt;&lt;span class="p"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;gla&lt;/span&gt; :&lt;span class="nx"&gt;GV&lt;/span&gt; &lt;span class="p"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;merges&lt;/span&gt; &lt;span class="p"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;glg&lt;/span&gt; :&lt;span class="nx"&gt;GV&lt;/span&gt; &lt;span class="p"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;merges&lt;/span&gt; &lt;span class="p"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>解决phpqa和fugitive不兼容的问题</title><link>http://0x3f.org/posts/solve-the-incompatablility-between-fugitive-and-phpqa/</link><pubDate>Wed, 18 Oct 2017 11:05:12 +0000</pubDate><guid>http://0x3f.org/posts/solve-the-incompatablility-between-fugitive-and-phpqa/</guid><description>&lt;p&gt;在&lt;code&gt;:Gstatus&lt;/code&gt;中查看diff时，报错：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Error detected while processing function Phpqa#PhpLint:&lt;br&gt;
line 8:&lt;br&gt;
E684: list index out of range: 0&lt;br&gt;
E116: Invalid arguments for function match(l:php_list[0],&amp;ldquo;No syntax errors&amp;rdquo;) == -1&lt;br&gt;
E15: Invalid expression: 0 != v:shell_error &amp;amp;&amp;amp; match(l:php_list[0],&amp;ldquo;No syntax errors&amp;rdquo;) == -1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是phpqa的bug，有人创建了PR，但作者没有合并，需要手工合并：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -L https://github.com/joonty/vim-phpqa/pull/43.patch &lt;span class="p"&gt;|&lt;/span&gt; git am
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>读完《美的历程》</title><link>http://0x3f.org/posts/after-reading-historical-evolution-of-aesthetics/</link><pubDate>Mon, 25 Sep 2017 16:43:08 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-historical-evolution-of-aesthetics/</guid><description>&lt;p&gt;这是我读过的第一本美学书。梳理了中国文艺和审美发展的历史脉络，浅显易懂。&lt;/p&gt;
&lt;p&gt;多读点美学还是很有必要的，能减少点俗气，那就最好了。&lt;/p&gt;</description></item><item><title>为什么不应该给表名加前缀</title><link>http://0x3f.org/posts/why-prefixes-are-not-needed-for-table-names/</link><pubDate>Mon, 25 Sep 2017 14:12:41 +0000</pubDate><guid>http://0x3f.org/posts/why-prefixes-are-not-needed-for-table-names/</guid><description>&lt;p&gt;表前缀是个过时的东西。在计算机资源比较昂贵的时代，出于节约成本的需要，会把多个系统的数据放在同一个数据库实例里，所以才会用前缀区分。如今各种云的普及，使这个问题早已经不存在，大家的资源都是冗余的，没有人会把多个系统的表放到同一个库里，这会给运维带来不必要的麻烦。&lt;/p&gt;
&lt;p&gt;然而身边总是会遇到胶柱鼓瑟的人，知其然而不知其所以然。表前缀既非必要，又会导致一些问题。&lt;/p&gt;
&lt;p&gt;其一是写代码时的困扰。比如我经常会在用查询构造器时忘了给表别名加前缀，直到程序报错才突然想起来。&lt;/p&gt;
&lt;p&gt;其二是代码重构的问题。在构造SQL语句的过程中，总是免不了会写原生的语句，这时就得写死表前缀。如果将来表前缀发生变化，重构代码时会麻烦而容易出错。&lt;/p&gt;</description></item><item><title>用AlfredTweet发推</title><link>http://0x3f.org/posts/tweet-with-alfredtweet/</link><pubDate>Sun, 17 Sep 2017 09:26:41 +0000</pubDate><guid>http://0x3f.org/posts/tweet-with-alfredtweet/</guid><description>&lt;p&gt;AlfredTweet是用来解决“最后一公里”问题的东西，有了它就可以随时发推了。&lt;/p&gt;
&lt;p&gt;需要修改源码指定代理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// twitteroauth.php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$postfields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLOPT_HTTPPROXYTUNNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLOPT_PROXY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;127.0.0.1:1086&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLOPT_PROXYTYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLPROXY_SOCKS5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>看完《汉书》</title><link>http://0x3f.org/posts/after-reading-han-shu/</link><pubDate>Sun, 10 Sep 2017 23:34:19 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-han-shu/</guid><description>&lt;p&gt;一周前读完了《汉书》。&lt;/p&gt;
&lt;p&gt;因为&lt;a href="http://0x3f.org/post/after-reading-tong-jian/"&gt;读过《资治通鉴》&lt;/a&gt;，这次并没有发现太多新鲜的东西，印象最深的是班氏父子的严谨，超过了两个司马。比如对于成帝的死，作为通史的《通鉴》居然写得比断代的《汉书》还详细，对于史书，详和实似乎是一对矛盾，前者自然更好看，而后者显然更严谨。&lt;/p&gt;
&lt;p&gt;秦汉之际，中国先后完成了两次宏大的社会实践。一次是秦的法家实践，一次是王莽的儒家改制。历史先后把机会给了构成中国日后民族性格最主要的两个思想流派，又用残酷的现实给这两个处处针锋相对的对头以当头棒喝。两家对对方缺陷的研究都在对方的失败里得到印证，而同时对自身的问题又都视而不见。这是非常戏剧性的一幕，儒法之争作为中国两千年政治的基本矛盾和规律，在一开始就被证明谁都不能独力承担给这个国家指明出路的责任。&lt;/p&gt;
&lt;p&gt;按照钱穆在《中国历代政治得失》里的说法，昂扬向上的知识分子在先秦百家争鸣最大成就的儒法两家全部失败后就颓了，怀疑和茫然蔓延开来，第一帝国也由此走向衰亡。而从另一角度，李泽厚在《美的历程》里却认为，社会实践的失败引发了思想的解放和自我意识的觉醒，第一帝国在政治上的失败并没有影响其文化向心力，胡尘狼烟中的北方仍以文弱江南为衣冠正朔所在。&lt;/p&gt;
&lt;p&gt;对于接下来的《后汉书》，我的期待不高，凭借门阀起家的光武帝一改前汉打压豪强的政策，章帝之后再无中兴，然后是在无休止的宦戚之争、鲜卑盗边和羌乱中回响的桓灵的叹息。&lt;/p&gt;
&lt;p&gt;第一帝国在巅峰中死去。&lt;/p&gt;</description></item><item><title>什么是docker</title><link>http://0x3f.org/posts/what-is-docker/</link><pubDate>Thu, 07 Sep 2017 15:31:11 +0000</pubDate><guid>http://0x3f.org/posts/what-is-docker/</guid><description>&lt;h2 id="什么是docker"&gt;什么是docker&lt;/h2&gt;
&lt;p&gt;docker是一种容器，&lt;a href="http://www.infoq.com/cn/articles/container-landscape-2016"&gt;这篇文章&lt;/a&gt;对容器的定义是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;容器是一组运行在Linux操作系统上并使用命名空间进程进行分隔的进程，有了容器就无需再启动和维护虚拟机。与虚拟机技术相比，容器的最大不同之处在于打包格式和可移植性。构建容器的目的在于为现代基础设施降低占用空间和启动时间、提供重用性、更好地利用服务器资源，并更好地集成到整个开发生态系统中（例如持续集成和交付生命周期）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;容器相对于虚拟机有以下优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更高效地利用系统资源&lt;/li&gt;
&lt;li&gt;更快的启动速度&lt;/li&gt;
&lt;li&gt;一致的运行环境&lt;/li&gt;
&lt;li&gt;持续的交付和部署&lt;/li&gt;
&lt;li&gt;更轻松的迁移&lt;/li&gt;
&lt;li&gt;维护和扩展的便利性&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;h3 id="镜像"&gt;镜像&lt;/h3&gt;
&lt;p&gt;Docker 镜像是一个特殊的文件系统，除了提供容器运行时所需的程序、库、资源、配置等文件外，还包含了一些为运行时准备的一些配置参数（如匿名卷、环境变量、用户等）。镜像不包含任何动态数据，其内容在构建之后也不会被改变。&lt;/p&gt;
&lt;p&gt;镜像分为黑箱镜像和dockerfile。&lt;/p&gt;
&lt;p&gt;前者通过实际创建和配置docker容器并通过&lt;code&gt;docker commit&lt;/code&gt;记录每个版本的变更，优点是简单直观，缺点是不能记录在基础镜像上做了哪些操作，并且在多次修改之后，镜像会变得很臃肿。&lt;/p&gt;
&lt;p&gt;dockerfile是镜像的配置文件，部署时docker根据配置内容生成容器，优点是可以清楚地记录每次修改的内容、镜像体积很小，缺点是编写时比较复杂。&lt;/p&gt;
&lt;h3 id="容器"&gt;容器&lt;/h3&gt;
&lt;p&gt;容器是镜像运行的实体。&lt;/p&gt;
&lt;h3 id="仓库"&gt;仓库&lt;/h3&gt;
&lt;p&gt;分发镜像的服务。&lt;/p&gt;
&lt;h3 id="编排"&gt;编排&lt;/h3&gt;
&lt;p&gt;容器的编排包含如下一系列任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调度（包括部署、复制、扩展、复活、重新调度、升级、降级等）&lt;/li&gt;
&lt;li&gt;资源管理（内存、CPU、存储空间、端口、IP、镜像等）&lt;/li&gt;
&lt;li&gt;服务管理（即使用标签、分组、命名空间、负载均衡和准备就绪检查将多个容器编排在一起）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;我在黑苹果下安装。Mac下安装docker有两种方式：Docker for Mac或Docker Toolbox。前者最简单，后者在前者的系统要求不能被满足的情况下使用。后者的卸载比较麻烦，具体参照&lt;a href="https://github.com/widuu/chinese_docker/blob/master/installation/mac.md"&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;我用前种方式安装，启动时报错：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;com.docker.osx.hyperkit.linux failed to start&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;解决方法是到BIOS里打开VT特性，有说法说黑苹果不支持VT，我这里是可以的。&lt;/p&gt;
&lt;h3 id="镜像加速器"&gt;镜像加速器&lt;/h3&gt;
&lt;p&gt;一般用阿里云的镜像服务。&lt;/p&gt;
&lt;h2 id="docker的使用"&gt;docker的使用&lt;/h2&gt;
&lt;h3 id="拉取镜像"&gt;拉取镜像&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker pull base/archlinux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="列出镜像"&gt;列出镜像&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker images
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="创建容器"&gt;创建容器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --name arch --it base/archlinux bash
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="终止容器"&gt;终止容器&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;exit&lt;/code&gt;或&lt;code&gt;ctrl-d&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="启动已终止容器"&gt;启动已终止容器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker start arch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="attach运行中的容器"&gt;attach运行中的容器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker attach arch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="detach运行中的容器"&gt;detach运行中的容器&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ctrl+p ctrl+q&lt;/code&gt;或者：&lt;/p&gt;</description></item><item><title>让hexo使用小写文件名</title><link>http://0x3f.org/posts/let-hexo-use-lowercase-filename/</link><pubDate>Tue, 15 Aug 2017 13:25:50 +0000</pubDate><guid>http://0x3f.org/posts/let-hexo-use-lowercase-filename/</guid><description>&lt;p&gt;hexo在生成tag目录时默认保持大小写，如果tag名称掺杂了大小写，会导致用tag索引文章的链接无法访问。解决的办法是强制hexo使用小写的文件或目录名，修改&lt;code&gt;_config.yml&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;filename_case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;即便如此，还要把之前生成的结果从托管服务器上删除，不过在Mac这样的不区分大小写的文件系统中，直接部署新生成的结果是无效的，这时需要删除hexo目录下的&lt;code&gt;.deploy_git&lt;/code&gt;目录并重新部署：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf .deploy_git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hexo clean
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hexo d -g
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>用vim-test简化单元测试的编写</title><link>http://0x3f.org/posts/make-writing-unit-tests-easier-with-vim-test/</link><pubDate>Mon, 14 Aug 2017 16:43:59 +0000</pubDate><guid>http://0x3f.org/posts/make-writing-unit-tests-easier-with-vim-test/</guid><description>&lt;p&gt;vim-test允许在Vim中直接执行一个或多个单元测试，并使用预设的或自定义的执行策略。&lt;/p&gt;
&lt;p&gt;例如，命令&lt;code&gt;:TestNearest&lt;/code&gt;可以执行当前测试文件中离光标最近的一个测试方法。而&lt;code&gt;:TestFile&lt;/code&gt;、&lt;code&gt;:TestSuite&lt;/code&gt;和&lt;code&gt;:TestLast&lt;/code&gt;分别执行整个测试文件、测试项目和最近一次执行过的测试。这在编写测试代码时能很大地提高效率。&lt;/p&gt;
&lt;p&gt;执行策略是执行测试的方式和环境。例如缺省状态下，将使用&lt;code&gt;:!&lt;/code&gt;执行测试命令，这会从Vim切换回终端。而在MacVim下，可以选择在iTerm或者系统自带的Terminal中执行。&lt;/p&gt;</description></item><item><title>把博客字体改成了方正北魏楷书</title><link>http://0x3f.org/posts/set-blog-webfont-to-fzbeiweikaishu/</link><pubDate>Mon, 14 Aug 2017 16:05:30 +0000</pubDate><guid>http://0x3f.org/posts/set-blog-webfont-to-fzbeiweikaishu/</guid><description>&lt;p&gt;我曾说过&lt;a href="http://0x3f.org/post/best-practices-of-calibre-on-formatting/"&gt;方正北魏楷书是最佳的阅读字体&lt;/a&gt;，不过后来感觉长时间阅读的体验还是普通的楷体更好。但这并不妨碍在Reeder、博客这种短时阅读场合突出页面的设计感。&lt;/p&gt;
&lt;p&gt;今天把博客（hexo）的webfont改成了方正北魏楷书，用font-spider压缩后，从13M缩减到1.4M。方法是这样的：&lt;/p&gt;
&lt;p&gt;首先把完整的字体复制到主题的字体目录中（themes/crisp/source/fonts），文件名为&lt;code&gt;FZBeiWeiKaiShu-full.ttf&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在CSS中加入webfont配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;font-family&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;FZBeiWeiKaiShu&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;src&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;../fonts/FZBeiWeiKaiShu.ttf&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;truetype&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;../fonts/FZBeiWeiKaiShu-full.ttf&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;truetype&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;FZBeiWeiKaiShu.ttf&lt;/code&gt;是压缩后的字体文件名，这样访问时浏览器会优先下载压缩后的字体。&lt;/p&gt;
&lt;p&gt;然后把CSS中使用字体的地方都指定为&lt;code&gt;FZBeiWeiKaiShu&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在博客根目录下创建脚本&lt;code&gt;update_fonts.sh&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hexo clean
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hexo g
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find public -name &lt;span class="s2"&gt;&amp;#34;*.html&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;xargs sed -i &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s#/styles/crisp.css#&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Projects/blog/public/styles/crisp.css#g&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find public -name &lt;span class="s2"&gt;&amp;#34;*.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;xargs font-spider
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp -f public/fonts/FZBeiWeiKaiShu.ttf themes/crisp/source/fonts/FZBeiWeiKaiShu.ttf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hexo clean
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hexo s -g
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;除非用到新的字符，否则不需要经常更新字体。&lt;/p&gt;
&lt;p&gt;font-spider会提示一共使用了多少种字符，我这么多年也只用到三千多种，真是太没文化了。🤥&lt;/p&gt;</description></item><item><title>Mock Laravel的DB Facade的方法</title><link>http://0x3f.org/posts/how-to-mock-the-db-facade-of-laravel/</link><pubDate>Mon, 14 Aug 2017 15:51:41 +0000</pubDate><guid>http://0x3f.org/posts/how-to-mock-the-db-facade-of-laravel/</guid><description>&lt;p&gt;关于数据库操作是否应该mock的问题，我认为查询一般不应该mock，可以避免一些问题，但如果查询的结果可能影响到断言，就应该mock了。&lt;/p&gt;
&lt;p&gt;Laravel的DB facade完整的mock实例是这样的：&lt;/p&gt;
&lt;script src="https://gist.github.com/xbot/d0ace9c1ebdb161adf229c9a9c62f2bf.js"&gt;&lt;/script&gt;</description></item><item><title>用vim-laravel简化laravel下的开发</title><link>http://0x3f.org/posts/speed-up-artisan-with-vim-laravel/</link><pubDate>Fri, 11 Aug 2017 15:05:30 +0000</pubDate><guid>http://0x3f.org/posts/speed-up-artisan-with-vim-laravel/</guid><description>&lt;p&gt;vim-laravel是个极简而实用的插件，只提供一个&lt;code&gt;:Artisan&lt;/code&gt;命令。但它并不仅仅是&lt;code&gt;artisan&lt;/code&gt;的一个wrapper，还可以实现一些贴心的自动化，利如自动打开&lt;code&gt;artisan make:*&lt;/code&gt;创建的文件。&lt;/p&gt;</description></item><item><title>用vim-php-namespace管理PHP的命名空间</title><link>http://0x3f.org/posts/manage-php-namespaces-with-vim-php-namespace/</link><pubDate>Fri, 11 Aug 2017 14:56:12 +0000</pubDate><guid>http://0x3f.org/posts/manage-php-namespaces-with-vim-php-namespace/</guid><description>&lt;p&gt;vim-php-namespace是个简单实用的插件，提供三种功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自动用use语句导入光标下的类&lt;/li&gt;
&lt;li&gt;自动把光标下的类名扩展成完整命名空间的格式&lt;/li&gt;
&lt;li&gt;自动排序use语句&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，还提供一个选项控制是否在导入类后自动排序use语句。&lt;/p&gt;</description></item><item><title>使neocomplete和ultisnips共用tab键的方法</title><link>http://0x3f.org/posts/reconcile-neocomplete-with-ultisnips/</link><pubDate>Fri, 11 Aug 2017 14:43:14 +0000</pubDate><guid>http://0x3f.org/posts/reconcile-neocomplete-with-ultisnips/</guid><description>&lt;p&gt;昨天用vim-clevertab换掉了supertab，但是实际使用中总是出莫名其妙的问题。看了一下插件源码，使用全局变量判断状态，这是个很不靠谱的方案，所以还是卸掉了。&lt;/p&gt;
&lt;p&gt;下面的配置可以很好的解决问题：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;UltiSnipsExpandTrigger&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;c-tab&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;UltiSnipsJumpForwardTrigger&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;c-tab&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;UltiSnipsJumpBackwardTrigger&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;s-tab&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;UltiSnipsSnippetsDir&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~/.vim/UltiSnips&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;ulti_expand_or_jump_res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;CleverTab&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&amp;#34;{{{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;UltiSnips&lt;/span&gt;#&lt;span class="nx"&gt;ExpandSnippetOrJump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;ulti_expand_or_jump_res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;pumvisible&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;\&amp;lt;c-n&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neocomplete&lt;/span&gt;#&lt;span class="nx"&gt;start_manual_complete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;&amp;#34;}}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;inoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nx"&gt;CleverTab&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;snoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;esc&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;:&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;UltiSnips&lt;/span&gt;#&lt;span class="nx"&gt;ExpandSnippetOrJump&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;ultisnips没有禁用按键映射的开关，而默认的映射会干扰上述配置，所以这里把默认的映射改成了&lt;code&gt;&amp;lt;c-tab&amp;gt;&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>GraphQL：RESTful之外的接口实现方案</title><link>http://0x3f.org/posts/graphql-vs-restful/</link><pubDate>Tue, 01 Aug 2017 17:36:27 +0000</pubDate><guid>http://0x3f.org/posts/graphql-vs-restful/</guid><description>&lt;p&gt;和RESTfull一样，GraphQL也是一种基于HTTP的接口实现方式。它区别于前者的主要有两点：数据格式的自定义和请求的合并。&lt;/p&gt;
&lt;p&gt;本质上，GraphQL是为了解决RESTful中前后端在业务逻辑上的耦合关系。在RESTful中，接口是为前端具体的业务需求定制的，从实现什么样的功能，到返回哪些数据，都是既定的，所以很难被其它业务逻辑共用，即使可以共用，前端也必须发送多个请求到后端，因而造成资源浪费、效率下降。&lt;/p&gt;
&lt;p&gt;GraphQL实现的是一套逻辑积木，每个封装好的业务逻辑都是原子的，前端可以自由选择使用哪些，也可以定制返回数据的格式。并且这一切，都可以通过一次请求实现。&lt;/p&gt;
&lt;p&gt;当然，GraphQL也有一些短板。比如缓存，对于RESTfull接口，可以根据操作的幂等性实现负载均衡层面的缓存，而对于GraphQL，由于请求数据格式灵活且可能很大，请求会用POST方式发送，这样就必须改变缓存的实现方式。再一点是嵌套的层级问题，GraphQL的灵活性允许查询类型之间彼此嵌套，如果层级过多，可能导致严重的性能和可用性问题，因此需要注意限制嵌套的层级。还有就是GraphQL的实现复杂度比RESTful要高，需要权衡使用哪种实现方案。&lt;/p&gt;
&lt;p&gt;GraphQL用schema管理接口，可以根据业务等因素划分schema，例如需要权限验证的和公开的。每个schema包含两类接口：query和mutation，分别用来查询和变更数据。&lt;/p&gt;
&lt;p&gt;下面在Laravel中简单实现一个query接口。&lt;/p&gt;
&lt;p&gt;先安装&lt;a href="https://github.com/Folkloreatelier/laravel-graphql"&gt;folklore/graphql&lt;/a&gt;库。&lt;/p&gt;
&lt;p&gt;实现文章类型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;App\GraphQL\Type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;GraphQL\Type\Definition\Type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Folklore\GraphQL\Support\Type&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;GraphQLType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostType&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;GraphQLType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;nonNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;description&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;The id of the post&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;description&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Post title&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resolveTitleField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;post_title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;实现文章的查询逻辑：&lt;/p&gt;</description></item><item><title>用vim-plug换掉了vim-addon-manager</title><link>http://0x3f.org/posts/replaced-vam-with-vim-plug/</link><pubDate>Mon, 31 Jul 2017 22:44:16 +0000</pubDate><guid>http://0x3f.org/posts/replaced-vam-with-vim-plug/</guid><description>&lt;p&gt;四年零两个月前，我在Vim的邮件组中&lt;a href="https://groups.google.com/forum/#!topic/vim_use/P3xpaHr8-do"&gt;征询pathogen和vundle的优劣&lt;/a&gt;。一个人建议我试试VAM，语气幽怨——他是它的作者。&lt;/p&gt;
&lt;p&gt;试过之后就从pathogen迁移到了VAM，因为它兼有前者和vundle的优点，在当时，这是最好的插件管理器。就这样用了很久，期间还写了点脚本&lt;a href="http://0x3f.org/post/simplify-vim-addon-installation-issues/"&gt;简化插件的管理&lt;/a&gt;，VAM工作得很好。&lt;/p&gt;
&lt;p&gt;最近发现越来越多的插件的文档里提到vim-plug，亮点是支持并行安装和更新，这真是解决了VAM最大的痛点：我叠代了十年的vimrc里用了很多插件，串行的VAM每次更新都让我很痛苦。&lt;/p&gt;
&lt;p&gt;另外，vim-plug较VAM的另一个优势是简单。这倒不是说后者很难用，只是作者过于追求灵活性，导致有些工作实现起来相对更复杂。例如，有的插件安装之后需要做一些额外的操作，VAM需要自己实现回调函数，然后挂到post-install钩子上。而对于vim-plug，只需要在注册插件的地方增加一个选项。对于插件的懒加载，也是同样。&lt;/p&gt;
&lt;p&gt;VAM也有自己的优势。其中之一是可以自动处理依赖关系：当一个要被安装的插件依赖别的插件时，相应的依赖也会被自动安装。还有就是对多源的支持：既可以拉取github上的插件，也可以从vim.org或其它源安装。而vim-plug就只支持github。&lt;/p&gt;
&lt;p&gt;所以，vim-plug并没有全面超过VAM，只是没有明显的短板、功能又刚刚够用。&lt;/p&gt;</description></item><item><title>用choosewin.vim切换窗口</title><link>http://0x3f.org/posts/choosewin-vim/</link><pubDate>Sun, 30 Jul 2017 20:48:46 +0000</pubDate><guid>http://0x3f.org/posts/choosewin-vim/</guid><description>&lt;p&gt;输入&lt;code&gt;-&lt;/code&gt;显示每个窗口的hint，输入hint跳转，简单而高效：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvwyakdmzj30or0gan0m.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Python 2还是3是个纠结的问题</title><link>http://0x3f.org/posts/bothered-by-python-2-vs-3/</link><pubDate>Sun, 30 Jul 2017 08:40:11 +0000</pubDate><guid>http://0x3f.org/posts/bothered-by-python-2-vs-3/</guid><description>&lt;p&gt;前些天用denite取代unite，用&lt;code&gt;--with-python3&lt;/code&gt;重装了vim，结果发现vdebug只支持python 2。&lt;/p&gt;
&lt;p&gt;vim同时只能在py2和py3中选一个，据说可以通过重新编译python实现共存，但是我在编译py3的时候失败。&lt;/p&gt;
&lt;p&gt;neovim同时支持两个版本，但是尝试deoplete失败，报「Invalid Channel」的错误，似乎是python-neovim的锅。而且由于neovim内建lua、不支持&lt;code&gt;has('lua')&lt;/code&gt;，所以不能fall back到neocomplete。&lt;/p&gt;
&lt;p&gt;万般无奈，只好换回unite。&lt;/p&gt;</description></item><item><title>给Thinkpad X220装了黑苹果</title><link>http://0x3f.org/posts/installed-hackintosh-in-thinkpad-x220/</link><pubDate>Sat, 29 Jul 2017 17:44:16 +0000</pubDate><guid>http://0x3f.org/posts/installed-hackintosh-in-thinkpad-x220/</guid><description>&lt;p&gt;闲鱼上突然收到询价消息，于是突发奇想，在闲置很久的X220上装个黑苹果玩玩。&lt;/p&gt;
&lt;p&gt;过程很简单，参考这两个链接：&lt;a href="https://www.youtube.com/watch?v=e_VDC-wUXis"&gt;link1&lt;/a&gt;和&lt;a href="http://x220.mcdonnelltech.com"&gt;link2&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvwwwbzydj30sg0sg7be.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;内置的无线网卡不能驱动，用了个闲置的USB卡。蓝牙能用耳机，但不能airdrop。关机会变重启。此外没别的问题了。&lt;/p&gt;
&lt;p&gt;现在计算机性能真是过剩的，n年前的机器，除了机械硬盘慢了点，其它毫无压力。&lt;/p&gt;
&lt;p&gt;我在twitter上说：“似可再战三年。”&lt;/p&gt;</description></item><item><title>利用goyo.vim专注写作</title><link>http://0x3f.org/posts/distraction-free-writing-in-vim/</link><pubDate>Sat, 29 Jul 2017 16:48:45 +0000</pubDate><guid>http://0x3f.org/posts/distraction-free-writing-in-vim/</guid><description>&lt;p&gt;goyo.vim是给vim提供专注写作模式的插件，配合markdown效果不错：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvwwvhfjlj31400p0q6b.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;最好在单独的vim实例中使用，已发现和vim-workspace配合不好的情况。&lt;/p&gt;
&lt;p&gt;对markdown文件自动开启goyo的配置如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;auto_goyo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &amp;amp;&lt;span class="nx"&gt;ft&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;markdown&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Goyo&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;bufnr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Goyo&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b &amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;bufnr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;augroup&lt;/span&gt; &lt;span class="nx"&gt;goyo_markdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;autocmd&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;BufNewFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;BufRead&lt;/span&gt; * &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;auto_goyo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;augroup&lt;/span&gt; &lt;span class="nx"&gt;END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>用vim-workspace换掉了session.vim</title><link>http://0x3f.org/posts/replace-session-vim-with-vim-workspace/</link><pubDate>Wed, 19 Jul 2017 17:47:30 +0000</pubDate><guid>http://0x3f.org/posts/replace-session-vim-with-vim-workspace/</guid><description>&lt;p&gt;用session.vim一直有几个痛点。一是保存会话后，退出时仍然会提示保存。二是会话会记录vimrc，恢复会话后用的仍然是旧的配置。&lt;/p&gt;
&lt;p&gt;vim-workspace没有这些问题，而且实现了更多功能。&lt;/p&gt;</description></item><item><title>用neocomplete换掉了YouCompleteMe</title><link>http://0x3f.org/posts/replace-youcompleteme-with-neocomplete/</link><pubDate>Sat, 15 Jul 2017 10:29:48 +0000</pubDate><guid>http://0x3f.org/posts/replace-youcompleteme-with-neocomplete/</guid><description>&lt;p&gt;在尝试了多种方案后，我又一次换掉了自动补全插件。&lt;/p&gt;
&lt;p&gt;工具应该是能提高生产力的，而不是相反，很长一段时间以来，YouCompleteMe带给我的却是个疑惑，真不知道这个东东到底是提高了我的生产力，还是反之。自动补全在提高输入速度和准确度上都有助益，但是有时候补全选项弹出的又很慢。&lt;/p&gt;
&lt;p&gt;测试了nvim-complete-manager+LanguageClient-neovim+LanguageServer-php-neovim、deoplete+phpcd、deoplete+padawan、neocomplete+phpcomplete-extended，效果都非常不理想。最后选择了neocomplete+phpcomplete，速度可以接受，表现比YCM稳定，功能该有的都有。&lt;/p&gt;
&lt;h3 id="相关阅读"&gt;相关阅读：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/make-youcompleteme-ultisnips-compatible/"&gt;How to Make YouCompleteMe Compatible with UltiSnips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/neocomplcache-vim/"&gt;Vim的终极自动补全插件：NeoComplCache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>LeaderF，也许是Vim最好的模糊查询插件</title><link>http://0x3f.org/posts/leaderf-currently-the-best-fuzzy-finder-of-vim/</link><pubDate>Thu, 13 Jul 2017 16:45:15 +0000</pubDate><guid>http://0x3f.org/posts/leaderf-currently-the-best-fuzzy-finder-of-vim/</guid><description>&lt;p&gt;之前&lt;a href="http://0x3f.org/post/ctrlp-vs-unite-vs-command-t-vs-fuzzyfinder/"&gt;对比过几个模糊查询插件&lt;/a&gt;（Fuzzy Finder），最后选定了ctrlp。&lt;/p&gt;
&lt;p&gt;用了下&lt;a href="https://github.com/Yggdroot/LeaderF"&gt;LeaderF&lt;/a&gt;，在速度和匹配的准确度上都明显超过了ctrlp，所以用它换掉了后者。&lt;/p&gt;
&lt;p&gt;只是在交互方式上，我更喜欢ctrlp，文件列表高度是动态变化的，最匹配的行和输入焦点都在窗口的最下方。LeaderF是定高的，最匹配的行在最上方，个人认为不如前者自然。&lt;/p&gt;
&lt;p&gt;能解决痛点的才是好东西，什么时候能换掉YouCompleteMe就好了。&lt;/p&gt;</description></item><item><title>怎样测试PHP的Private或Protected方法</title><link>http://0x3f.org/posts/how-to-test-private-or-protected-methods-in-php/</link><pubDate>Mon, 03 Jul 2017 13:17:30 +0000</pubDate><guid>http://0x3f.org/posts/how-to-test-private-or-protected-methods-in-php/</guid><description>&lt;p&gt;利用闭包绑定：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$ctrlr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;UserController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$tester&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$runner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$tester&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;bindTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctrlr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$ctrlr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$runner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>白鹿原、外乡人和窗外</title><link>http://0x3f.org/posts/routine-talk-170629/</link><pubDate>Thu, 29 Jun 2017 22:51:52 +0000</pubDate><guid>http://0x3f.org/posts/routine-talk-170629/</guid><description>&lt;p&gt;&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvwyid54yj30wv0igdm7.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;今年端午恰好是开公众号一周年，成绩就不晒了，因为没有成绩，当初的目标好像一个都没实现，想著端午写几句话，结果又拖了一个月……&lt;/p&gt;
&lt;p&gt;这一年跌宕起伏，却是不足与人道，倒是最近看了两部剧，感觉还不错。&lt;/p&gt;
&lt;p&gt;《白鹿原》前段时间很火，我没看过原著，好像我骨子里不是个喜欢小说的，十几年前听说这本书的时候也没什么去读的冲动。这次看拍得还不错，就买了乐视的会员，每天追到凌晨一点。整体来说质量不错，阵容不算豪华，主演的几位演技都挺好，适合我这种没看过原著又很龟毛的。看过的就不用追了，影视剧永远赶不上原著。&lt;/p&gt;
&lt;p&gt;《外乡人》的知名度就差远了，我也是从豆瓣上翻高分剧翻出来的。几年前的一部冷门剧，题材就很冷，讲沪漂的。剧情贴近现实，演员的表演也很真实，分数就高在这儿了，能做到这两点的太少了。&lt;/p&gt;
&lt;p&gt;题图是我的窗外，前段时间天气好的时候拍的，Snapseed真是个好东西，嗯。&lt;/p&gt;</description></item><item><title>为每个GTK3应用指定单独的主题</title><link>http://0x3f.org/posts/specify-a-theme-for-each-gtk-3-app/</link><pubDate>Tue, 27 Jun 2017 15:37:43 +0000</pubDate><guid>http://0x3f.org/posts/specify-a-theme-for-each-gtk-3-app/</guid><description>&lt;p&gt;指定GVim 8使用Numix主题并最小程度影响既有的脚本、快捷键。&lt;/p&gt;
&lt;p&gt;我这里gvim安装在&lt;code&gt;/usr/bin/gvim&lt;/code&gt;，$PATH中&lt;code&gt;/usr/local/bin&lt;/code&gt;在&lt;code&gt;/usr/bin&lt;/code&gt;前面，所以在&lt;code&gt;/usr/local/bin&lt;/code&gt;下创建gvim：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;GTK_THEME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Numix /usr/bin/gvim &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;同理，对gvimdiff也做同样处理。&lt;/p&gt;</description></item><item><title>调校mycli</title><link>http://0x3f.org/posts/fine-tune-mycli/</link><pubDate>Mon, 26 Jun 2017 18:05:31 +0000</pubDate><guid>http://0x3f.org/posts/fine-tune-mycli/</guid><description>&lt;p&gt;做以下配置，使mycli按需使用pager，并在数据过多时不破坏表格格式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ~/.my.cnf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[client]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;pager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;less -FSXR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>用MySQL的全文检索实现相关性排序</title><link>http://0x3f.org/posts/fulltext-searching-in-mysql/</link><pubDate>Mon, 19 Jun 2017 23:10:41 +0000</pubDate><guid>http://0x3f.org/posts/fulltext-searching-in-mysql/</guid><description>&lt;p&gt;实现根据文章的关键词搜索出相关的文章，并按相关性排序。&lt;/p&gt;
&lt;p&gt;数据库版本是5.6.x，还不能像5.7那样支持中文的全文检索，所以另外创建一列保存关键词的编码。方法为base64转码并去掉「%」符号：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 转换关键词到全文检索的格式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param mixed $keywords 关键词数组或英文逗号分隔的字符串
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;encode_keywords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$keywords&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$keyword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;str_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$keyword&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;is_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$keywords&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$keywords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$keywords&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;array_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$encoder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$keywords&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;对该列创建全文检索的索引：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FULLTEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx_post_keywords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords_ft&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;查询语句：&lt;/p&gt;</description></item><item><title>CopyQ，也许是Linux最好的剪贴板管理工具</title><link>http://0x3f.org/posts/copyq/</link><pubDate>Mon, 19 Jun 2017 21:49:14 +0000</pubDate><guid>http://0x3f.org/posts/copyq/</guid><description>&lt;p&gt;我对剪贴板管理工具的核心需求有四个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;记录文本&lt;/li&gt;
&lt;li&gt;记录图片&lt;/li&gt;
&lt;li&gt;快速搜索&lt;/li&gt;
&lt;li&gt;独立软件包&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CopyQ是Linux上唯一满足这些需求的实现，虽然体验上跟Mac下的竞品还有差距。&lt;/p&gt;
&lt;p&gt;用法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;copyq&lt;/code&gt;：运行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;copyq menu&lt;/code&gt;：显示剪贴板历史管理菜单&lt;/li&gt;
&lt;li&gt;&lt;code&gt;copyq show&lt;/code&gt;：显示剪贴板历史管理窗口&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>手机锁屏后自动断开WiFi的解决办法</title><link>http://0x3f.org/posts/solve-the-auto-breaking-problem-of-huawei-e5573s/</link><pubDate>Sat, 17 Jun 2017 23:13:33 +0000</pubDate><guid>http://0x3f.org/posts/solve-the-auto-breaking-problem-of-huawei-e5573s/</guid><description>&lt;p&gt;我的iPhone 6总是在锁屏后不久就从华为E5573S断开，但是连接家里的WiFi不会有这个问题，iOS同版本的iPad mini 4连接E5573S也正常。&lt;/p&gt;
&lt;p&gt;两台机器里E5573S的连接属性界面有差异，iPhone 6里有「自动加入」等两个选项，这在同机其它WiFi连接里是没有的，iPad里也没有。所以猜测应该是iPhone里连接本身的问题，忽略掉该连接，再重新连，就好了。&lt;/p&gt;</description></item><item><title>用Tmux的控制模式提高生产力</title><link>http://0x3f.org/posts/improve-productivity-with-tmux-control-mode/</link><pubDate>Sun, 11 Jun 2017 10:40:06 +0000</pubDate><guid>http://0x3f.org/posts/improve-productivity-with-tmux-control-mode/</guid><description>&lt;p&gt;Tmux的控制模式（Control Mode）可以把tmux的窗口映射为本地虚拟终端的窗口，也就是说，用户可以像操作本地虚拟终端一样操作tmux。这对备受tmux的emacs风格的热键绑定折磨或需要嵌套tmux的人来说非常有用。&lt;/p&gt;
&lt;p&gt;在支持这个特性的虚拟终端（例如「iTerm」）里，执行&lt;code&gt;tmux -CC&lt;/code&gt;即可。当然也可以&lt;code&gt;tmux -CC a&lt;/code&gt;恢复会话。&lt;/p&gt;</description></item><item><title>用SwitchHosts!切换主机映射方案</title><link>http://0x3f.org/posts/switch-hosts-with-switchhosts/</link><pubDate>Sun, 11 Jun 2017 09:57:54 +0000</pubDate><guid>http://0x3f.org/posts/switch-hosts-with-switchhosts/</guid><description>&lt;p&gt;最近在Archlinux上开始用SwitchHosts!管理主机映射方案，它可能是Linux下做这件事的最好的工具了。&lt;/p&gt;
&lt;p&gt;在Mac下也用它替换掉了Gas Mask，因为支持Alfred Workflow。相对的缺点是不支持在状态栏图标上显示当前方案名称，不过Alfred里可以，一定程度上缓解了这个问题。&lt;/p&gt;</description></item><item><title>自定义GVIM 8标签栏样式的方法</title><link>http://0x3f.org/posts/how-to-customize-gvim8-tab-style/</link><pubDate>Sun, 04 Jun 2017 12:42:12 +0000</pubDate><guid>http://0x3f.org/posts/how-to-customize-gvim8-tab-style/</guid><description>&lt;p&gt;GVim 8用的是GTK 3，原来在&lt;code&gt;~/.gtkrc-2.0&lt;/code&gt;里加样式的方法不能用了。&lt;/p&gt;
&lt;p&gt;GTK 3的样式在&lt;code&gt;~/.config/gtk-3.0/gtk.css&lt;/code&gt;里：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt; * Adapt to the nova colorscheme
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;define-color&lt;/span&gt; &lt;span class="nt"&gt;VIM_BG_FIX&lt;/span&gt; &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;3C4C55&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;window&lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;vim-main-window&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;VIM_BG_FIX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;window&lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;vim-main-window&lt;/span&gt; &lt;span class="nt"&gt;notebook&lt;/span&gt; &lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#1E272C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;border-bottom-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;window&lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;vim-main-window&lt;/span&gt; &lt;span class="nt"&gt;notebook&lt;/span&gt; &lt;span class="nt"&gt;tab&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;border-bottom-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;window&lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;vim-main-window&lt;/span&gt; &lt;span class="nt"&gt;notebook&lt;/span&gt; &lt;span class="nt"&gt;tab&lt;/span&gt; &lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#7CBDC6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;window&lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;vim-main-window&lt;/span&gt; &lt;span class="nt"&gt;notebook&lt;/span&gt; &lt;span class="nt"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;checked&lt;/span&gt; &lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#7CBDC6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#1E272C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;查看GTK 3程序的样式结构的方法是用GTK Inspector：&lt;/p&gt;</description></item><item><title>网站签到的最佳实践</title><link>http://0x3f.org/posts/the-best-practice-of-checking-in/</link><pubDate>Wed, 24 May 2017 11:42:52 +0000</pubDate><guid>http://0x3f.org/posts/the-best-practice-of-checking-in/</guid><description>&lt;p&gt;v2ex、优酷、什么值得买用&lt;a href="https://qiandao.today"&gt;qiandao.today&lt;/a&gt;实现。优点是依赖少，速度快，支持的范围广，可扩展。缺点是对京东和京东金融无效。&lt;/p&gt;
&lt;p&gt;京东和京东金融使用&lt;a href="https://github.com/yidinghan/daily-signin"&gt;daily-signin&lt;/a&gt;。缺点是依赖docker，速度慢。&lt;/p&gt;
&lt;p&gt;淘宝签到没有有效的脚本，用&lt;a href="http://www.duoduodazhe.com/App/Web/Taobao-Coin/"&gt;淘金币一键领取&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;飞猪也没有有效脚本，手工签：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://trip.taobao.com/mytrip/?tvm=tvip"&gt;http://trip.taobao.com/mytrip/?tvm=tvip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://trip.taobao.com/mytrip/"&gt;http://trip.taobao.com/mytrip/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://h5.m.taobao.com/trip/member/index.html"&gt;http://h5.m.taobao.com/trip/member/index.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>通过比较截图检查网页变化</title><link>http://0x3f.org/posts/check-changes-of-webpage-by-comparing-screenshots/</link><pubDate>Sun, 30 Apr 2017 17:21:52 +0000</pubDate><guid>http://0x3f.org/posts/check-changes-of-webpage-by-comparing-screenshots/</guid><description>&lt;p&gt;有时候我们希望检查代码或数据的更新对网页产生的影响，如果能把这个过程集成到git等版本控制系统中，在提交成果的同时自动批量执行，将会极大地提高生产力。&lt;/p&gt;
&lt;p&gt;首先网页的截图可以用PhantomJS、Headless Chrome实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;webpage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://github.com/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;github.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;phantom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;图片的差异比较用GraphicsMagick实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gm compare old.png new.png -file diff.png -highlight-style assign
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;为方便查看，还可以把截图做成gif动图：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gm convert -delay &lt;span class="m"&gt;20&lt;/span&gt; old.png diff.png new.png diff.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>PHPUnit代码覆盖率的统计方法</title><link>http://0x3f.org/posts/how-to-count-code-coverage-of-phpunit/</link><pubDate>Sun, 30 Apr 2017 14:20:41 +0000</pubDate><guid>http://0x3f.org/posts/how-to-count-code-coverage-of-phpunit/</guid><description>&lt;p&gt;关于PHPUnit代码覆盖率的很多概念，官方文档中讲的十分清楚，本文仅就部分语焉不详的细节做些补充。&lt;/p&gt;
&lt;p&gt;虽然phpunit.xml不是必需，但每次都输入完整的命令很不方便，所以一般都要生成这个配置文件。用&lt;code&gt;phpunit --generate-configuration&lt;/code&gt;生成的phpunit.xml默认包含&lt;code&gt;forceCoversAnnotation=&amp;quot;true&amp;quot;&lt;/code&gt;，它表示必须在测试方法头部的注释里显式使用&lt;code&gt;@covers&lt;/code&gt;标签声明统计范围，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::&amp;lt;public&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::parseCallStack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::__construct
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::__callStatic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;testAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;否则在执行统计代码覆盖率的命令时，会报risk：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There was 1 risky test:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ox3f\LaravelUtils\Log\LogTest::testAll
This test does not have a @covers annotation but is expected to have one&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果希望单元测试覆盖全部代码、且不用一一显式声明，可以将此选项的值改成
&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>利用依赖注入Mock PHP的内建函数</title><link>http://0x3f.org/posts/mock-php-built-in-functions-using-dependency-injection/</link><pubDate>Sun, 30 Apr 2017 09:57:50 +0000</pubDate><guid>http://0x3f.org/posts/mock-php-built-in-functions-using-dependency-injection/</guid><description>&lt;h2 id="简述"&gt;简述&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://0x3f.org/post/mock-php-built-in-functions-using-namespace/"&gt;上篇文章&lt;/a&gt;讨论了如何利用命名空间实现对PHP内建函数的mocking，本文介绍另一种实现方法——依赖注入。&lt;/p&gt;
&lt;p&gt;出于编写可测试代码的需要，依赖注入是经常使用的一种技术。通过把代码中依赖的其它数据获取服务提取出来、和原有逻辑解耦，提高代码的可测试性。只需mock这些依赖并注入到测试对象中即可。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;h3 id="对原有代码的重构"&gt;对原有代码的重构&lt;/h3&gt;
&lt;p&gt;先把原有代码用依赖注入的方式重构（&lt;em&gt;为突出重点，省略了和上篇文章中重复的部分&lt;/em&gt;）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Ox3f\LaravelUtils\Services\Builtins&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Class Log
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @author donie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Log&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$builtins&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Builtin functions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;builtins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Builtins&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Parse the call stack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseCallStack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$traceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;debug_backtrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEBUG_BACKTRACE_PROVIDE_OBJECT&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;DEBUG_BACKTRACE_IGNORE_ARGS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;Builtins&lt;/code&gt;类的实现：&lt;/p&gt;</description></item><item><title>利用命名空间Mock PHP的内建函数</title><link>http://0x3f.org/posts/mock-php-built-in-functions-using-namespace/</link><pubDate>Sun, 30 Apr 2017 09:06:17 +0000</pubDate><guid>http://0x3f.org/posts/mock-php-built-in-functions-using-namespace/</guid><description>&lt;h2 id="简述"&gt;简述&lt;/h2&gt;
&lt;p&gt;Mock PHP的内建函数一般有两种方法：命名空间法和依赖注入法。&lt;/p&gt;
&lt;p&gt;命名空间法是利用PHP优先使用同命名空间内函数的特性，在测试对象的命名空间内重载内建函数来实现。前提是内建函数在被调用时没有使用命名空间，例如：&lt;code&gt;\debug_backtrace()&lt;/code&gt;是不能使用本方法的。&lt;/p&gt;
&lt;p&gt;上篇文章&lt;a href="http://0x3f.org/post/the-best-practice-of-logging-in-api-programming/"&gt;《接口编程中记录日志的最佳实践》&lt;/a&gt;中实现的日志类中，核心部分调用了&lt;code&gt;debug_backtrace()&lt;/code&gt;函数获取方法调用堆栈。下面讨论下如何利用命名空间法实现对此函数的mock。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;先看代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;span class="lnt"&gt;68
&lt;/span&gt;&lt;span class="lnt"&gt;69
&lt;/span&gt;&lt;span class="lnt"&gt;70
&lt;/span&gt;&lt;span class="lnt"&gt;71
&lt;/span&gt;&lt;span class="lnt"&gt;72
&lt;/span&gt;&lt;span class="lnt"&gt;73
&lt;/span&gt;&lt;span class="lnt"&gt;74
&lt;/span&gt;&lt;span class="lnt"&gt;75
&lt;/span&gt;&lt;span class="lnt"&gt;76
&lt;/span&gt;&lt;span class="lnt"&gt;77
&lt;/span&gt;&lt;span class="lnt"&gt;78
&lt;/span&gt;&lt;span class="lnt"&gt;79
&lt;/span&gt;&lt;span class="lnt"&gt;80
&lt;/span&gt;&lt;span class="lnt"&gt;81
&lt;/span&gt;&lt;span class="lnt"&gt;82
&lt;/span&gt;&lt;span class="lnt"&gt;83
&lt;/span&gt;&lt;span class="lnt"&gt;84
&lt;/span&gt;&lt;span class="lnt"&gt;85
&lt;/span&gt;&lt;span class="lnt"&gt;86
&lt;/span&gt;&lt;span class="lnt"&gt;87
&lt;/span&gt;&lt;span class="lnt"&gt;88
&lt;/span&gt;&lt;span class="lnt"&gt;89
&lt;/span&gt;&lt;span class="lnt"&gt;90
&lt;/span&gt;&lt;span class="lnt"&gt;91
&lt;/span&gt;&lt;span class="lnt"&gt;92
&lt;/span&gt;&lt;span class="lnt"&gt;93
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;Ox3f\LaravelUtils\Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;PHPUnit\Framework\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Illuminate\Support\Facades\Auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Illuminate\Support\Facades\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Illuminate\Support\Facades\Log&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Ox3f\LaravelUtils\Log\Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$calledInController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debug_backtrace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="nv"&gt;$calledInController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$calledInController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/vendor\/xbot\/laravel-utils\/src\/Log\/Log.php&amp;#34;,&amp;#34;line&amp;#34;:85,&amp;#34;function&amp;#34;:&amp;#34;parseCallStack&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;Ox3f\\\LaravelUtils\\\Log\\\Log&amp;#34;,&amp;#34;object&amp;#34;:{},&amp;#34;type&amp;#34;:&amp;#34;-&amp;gt;&amp;#34;},{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/app\/Api\/V1\/Controllers\/WorkController.php&amp;#34;,&amp;#34;line&amp;#34;:29,&amp;#34;function&amp;#34;:&amp;#34;saveInput&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;Ox3f\\\LaravelUtils\\\Log\\\Log&amp;#34;,&amp;#34;type&amp;#34;:&amp;#34;::&amp;#34;},{&amp;#34;function&amp;#34;:&amp;#34;save&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;App\\\Api\\\V1\\\Controllers\\\WorkController&amp;#34;,&amp;#34;object&amp;#34;:{},&amp;#34;type&amp;#34;:&amp;#34;-&amp;gt;&amp;#34;},{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/vendor\/laravel\/framework\/src\/Illuminate\/Routing\/Controller.php&amp;#34;,&amp;#34;line&amp;#34;:55,&amp;#34;function&amp;#34;:&amp;#34;call_user_func_array&amp;#34;},{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/vendor\/laravel\/framework\/src\/Illuminate\/Routing\/ControllerDispatcher.php&amp;#34;,&amp;#34;line&amp;#34;:44,&amp;#34;function&amp;#34;:&amp;#34;callAction&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;Illuminate\\\Routing\\\Controller&amp;#34;,&amp;#34;object&amp;#34;:{},&amp;#34;type&amp;#34;:&amp;#34;-&amp;gt;&amp;#34;}]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/vendor\/xbot\/laravel-utils\/src\/Log\/Log.php&amp;#34;,&amp;#34;line&amp;#34;:85,&amp;#34;function&amp;#34;:&amp;#34;parseCallStack&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;Ox3f\\\LaravelUtils\\\Log\\\Log&amp;#34;,&amp;#34;object&amp;#34;:{},&amp;#34;type&amp;#34;:&amp;#34;-&amp;gt;&amp;#34;},{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/app\/Notation.php&amp;#34;,&amp;#34;line&amp;#34;:21,&amp;#34;function&amp;#34;:&amp;#34;saveInput&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;Ox3f\\\LaravelUtils\\\Log\\\Log&amp;#34;,&amp;#34;type&amp;#34;:&amp;#34;::&amp;#34;},{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/app\/Api\/V1\/Controllers\/NotationController.php&amp;#34;,&amp;#34;line&amp;#34;:32,&amp;#34;function&amp;#34;:&amp;#34;incrNo&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;App\\\Notation&amp;#34;,&amp;#34;type&amp;#34;:&amp;#34;::&amp;#34;},{&amp;#34;function&amp;#34;:&amp;#34;save&amp;#34;,&amp;#34;class&amp;#34;:&amp;#34;App\\\Api\\\V1\\\Controllers\\\NotationController&amp;#34;,&amp;#34;object&amp;#34;:{},&amp;#34;type&amp;#34;:&amp;#34;-&amp;gt;&amp;#34;},{&amp;#34;file&amp;#34;:&amp;#34;\/Users\/xbot\/Sites\/sample-project\/vendor\/laravel\/framework\/src\/Illuminate\/Routing\/Controller.php&amp;#34;,&amp;#34;line&amp;#34;:55,&amp;#34;function&amp;#34;:&amp;#34;call_user_func_array&amp;#34;}]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogTest&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;jim&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::saveInput
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::saveOutput
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::parseCallStack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::getInstance
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::__construct
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @covers Ox3f\LaravelUtils\Log\Log::__callStatic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;testAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="nv"&gt;$calledInController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// test being called in a plain method
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$calledInController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jim | App\Notation::incrNo | Input:1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;saveInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jim | App\Notation::incrNo | Output:2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;saveOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// test being called in a controller action
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$calledInController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;api/user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;except&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jim | api/user | Input:{&amp;#34;id&amp;#34;:18}&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;saveInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;api/user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jim | api/user | Output:2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;saveOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;api/user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jim | api/user | this is an error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;this is an error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;最重要的是第一行，这里把测试类的命名空间设置得和测试对象一致，这样在下面重载的&lt;code&gt;debug_backtrace()&lt;/code&gt;函数就会在测试对象中被优先使用。&lt;/p&gt;</description></item><item><title>接口编程中记录日志的最佳实践</title><link>http://0x3f.org/posts/the-best-practice-of-logging-in-api-programming/</link><pubDate>Tue, 25 Apr 2017 15:50:41 +0000</pubDate><guid>http://0x3f.org/posts/the-best-practice-of-logging-in-api-programming/</guid><description>&lt;h2 id="解决什么问题"&gt;解决什么问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;快速定位日志&lt;/li&gt;
&lt;li&gt;降低记录成本&lt;/li&gt;
&lt;li&gt;提高代码可读性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;日志框架是项目开始阶段应该最先搭建好的内容之一，有助于极大地节约以后解决问题的时间和成本。但这也是最让我头疼的问题之一，因为记日志不光包括用什么记、怎么记，也包括记什么内容，这恰恰是最容易被忽略的问题。&lt;/p&gt;
&lt;p&gt;一条好的日志需要做到能让问题的跟踪者快速定位它在程序中的位置且包含关键数据。工作中不乏这样的团队成员，在移交接口问题的时候没有主动提供关键信息的意识，所谓关键信息，是指像问题发生的环境、接口名、传递的实参和返回结果这样的内容，使得面向契约编程本来是很好的开发模式，却得不到最好的应用。这时我们可以从自己接口的日志中得到一些弥补。&lt;/p&gt;
&lt;p&gt;但是日志的记录不应该占用很大的代码量，一来降低了代码的可读性，二来会耗费太多的时间精力。&lt;/p&gt;
&lt;p&gt;本文目的在于讨论一种日志记录的最佳实践方式，使得可以兼顾以上这些问题。&lt;/p&gt;
&lt;h2 id="实践"&gt;实践&lt;/h2&gt;
&lt;p&gt;这里针对Laravel实现一个日志工具类，实现以下功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;兼容Laravel自己的日志系统&lt;/li&gt;
&lt;li&gt;自动记录关键的业务数据&lt;/li&gt;
&lt;li&gt;自动记录日志所属的接口名&lt;/li&gt;
&lt;li&gt;自动记录接口的实参&lt;/li&gt;
&lt;li&gt;记录接口的返回值&lt;/li&gt;
&lt;li&gt;生成简洁规范的日志内容&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt; 10
&lt;/span&gt;&lt;span class="lnt"&gt; 11
&lt;/span&gt;&lt;span class="lnt"&gt; 12
&lt;/span&gt;&lt;span class="lnt"&gt; 13
&lt;/span&gt;&lt;span class="lnt"&gt; 14
&lt;/span&gt;&lt;span class="lnt"&gt; 15
&lt;/span&gt;&lt;span class="lnt"&gt; 16
&lt;/span&gt;&lt;span class="lnt"&gt; 17
&lt;/span&gt;&lt;span class="lnt"&gt; 18
&lt;/span&gt;&lt;span class="lnt"&gt; 19
&lt;/span&gt;&lt;span class="lnt"&gt; 20
&lt;/span&gt;&lt;span class="lnt"&gt; 21
&lt;/span&gt;&lt;span class="lnt"&gt; 22
&lt;/span&gt;&lt;span class="lnt"&gt; 23
&lt;/span&gt;&lt;span class="lnt"&gt; 24
&lt;/span&gt;&lt;span class="lnt"&gt; 25
&lt;/span&gt;&lt;span class="lnt"&gt; 26
&lt;/span&gt;&lt;span class="lnt"&gt; 27
&lt;/span&gt;&lt;span class="lnt"&gt; 28
&lt;/span&gt;&lt;span class="lnt"&gt; 29
&lt;/span&gt;&lt;span class="lnt"&gt; 30
&lt;/span&gt;&lt;span class="lnt"&gt; 31
&lt;/span&gt;&lt;span class="lnt"&gt; 32
&lt;/span&gt;&lt;span class="lnt"&gt; 33
&lt;/span&gt;&lt;span class="lnt"&gt; 34
&lt;/span&gt;&lt;span class="lnt"&gt; 35
&lt;/span&gt;&lt;span class="lnt"&gt; 36
&lt;/span&gt;&lt;span class="lnt"&gt; 37
&lt;/span&gt;&lt;span class="lnt"&gt; 38
&lt;/span&gt;&lt;span class="lnt"&gt; 39
&lt;/span&gt;&lt;span class="lnt"&gt; 40
&lt;/span&gt;&lt;span class="lnt"&gt; 41
&lt;/span&gt;&lt;span class="lnt"&gt; 42
&lt;/span&gt;&lt;span class="lnt"&gt; 43
&lt;/span&gt;&lt;span class="lnt"&gt; 44
&lt;/span&gt;&lt;span class="lnt"&gt; 45
&lt;/span&gt;&lt;span class="lnt"&gt; 46
&lt;/span&gt;&lt;span class="lnt"&gt; 47
&lt;/span&gt;&lt;span class="lnt"&gt; 48
&lt;/span&gt;&lt;span class="lnt"&gt; 49
&lt;/span&gt;&lt;span class="lnt"&gt; 50
&lt;/span&gt;&lt;span class="lnt"&gt; 51
&lt;/span&gt;&lt;span class="lnt"&gt; 52
&lt;/span&gt;&lt;span class="lnt"&gt; 53
&lt;/span&gt;&lt;span class="lnt"&gt; 54
&lt;/span&gt;&lt;span class="lnt"&gt; 55
&lt;/span&gt;&lt;span class="lnt"&gt; 56
&lt;/span&gt;&lt;span class="lnt"&gt; 57
&lt;/span&gt;&lt;span class="lnt"&gt; 58
&lt;/span&gt;&lt;span class="lnt"&gt; 59
&lt;/span&gt;&lt;span class="lnt"&gt; 60
&lt;/span&gt;&lt;span class="lnt"&gt; 61
&lt;/span&gt;&lt;span class="lnt"&gt; 62
&lt;/span&gt;&lt;span class="lnt"&gt; 63
&lt;/span&gt;&lt;span class="lnt"&gt; 64
&lt;/span&gt;&lt;span class="lnt"&gt; 65
&lt;/span&gt;&lt;span class="lnt"&gt; 66
&lt;/span&gt;&lt;span class="lnt"&gt; 67
&lt;/span&gt;&lt;span class="lnt"&gt; 68
&lt;/span&gt;&lt;span class="lnt"&gt; 69
&lt;/span&gt;&lt;span class="lnt"&gt; 70
&lt;/span&gt;&lt;span class="lnt"&gt; 71
&lt;/span&gt;&lt;span class="lnt"&gt; 72
&lt;/span&gt;&lt;span class="lnt"&gt; 73
&lt;/span&gt;&lt;span class="lnt"&gt; 74
&lt;/span&gt;&lt;span class="lnt"&gt; 75
&lt;/span&gt;&lt;span class="lnt"&gt; 76
&lt;/span&gt;&lt;span class="lnt"&gt; 77
&lt;/span&gt;&lt;span class="lnt"&gt; 78
&lt;/span&gt;&lt;span class="lnt"&gt; 79
&lt;/span&gt;&lt;span class="lnt"&gt; 80
&lt;/span&gt;&lt;span class="lnt"&gt; 81
&lt;/span&gt;&lt;span class="lnt"&gt; 82
&lt;/span&gt;&lt;span class="lnt"&gt; 83
&lt;/span&gt;&lt;span class="lnt"&gt; 84
&lt;/span&gt;&lt;span class="lnt"&gt; 85
&lt;/span&gt;&lt;span class="lnt"&gt; 86
&lt;/span&gt;&lt;span class="lnt"&gt; 87
&lt;/span&gt;&lt;span class="lnt"&gt; 88
&lt;/span&gt;&lt;span class="lnt"&gt; 89
&lt;/span&gt;&lt;span class="lnt"&gt; 90
&lt;/span&gt;&lt;span class="lnt"&gt; 91
&lt;/span&gt;&lt;span class="lnt"&gt; 92
&lt;/span&gt;&lt;span class="lnt"&gt; 93
&lt;/span&gt;&lt;span class="lnt"&gt; 94
&lt;/span&gt;&lt;span class="lnt"&gt; 95
&lt;/span&gt;&lt;span class="lnt"&gt; 96
&lt;/span&gt;&lt;span class="lnt"&gt; 97
&lt;/span&gt;&lt;span class="lnt"&gt; 98
&lt;/span&gt;&lt;span class="lnt"&gt; 99
&lt;/span&gt;&lt;span class="lnt"&gt;100
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;Ox3f\LaravelUtils\Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Illuminate\Support\Facades\Log&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Illuminate\Support\Facades\Auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Illuminate\Support\Facades\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Class Log
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @author donie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Log&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Identity of the log, username by default.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$referer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Request path for RESTful APIs, method name for ordinary class methods.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$isHttp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// True for RESTful APIs, otherwise, false.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$callStackParsed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Whether call stack has been parsed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;anonymous&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Parse the call stack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseCallStack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$traceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;debug_backtrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEBUG_BACKTRACE_PROVIDE_OBJECT&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;DEBUG_BACKTRACE_IGNORE_ARGS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;referer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;isHttp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$traceInfo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$callInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$callInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;__CLASS__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/Controller$/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$callInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;referer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;isHttp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;referer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$callInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$callInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$callInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;callStackParsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Wrapper of the laravel log facade
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__callStatic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;callStackParsed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;parseCallStack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$referer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;referer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;LaravelLog&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$referer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$msg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;callStackParsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Save parameters of the request or arguments of the method to log at debug level
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param mixed $args Empty for HTTP calls, needed for ordinary class methods
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;saveInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;parseCallStack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;isHttp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;except&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Input:&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Save the output to log at debug level
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param mixed $result Result to be saved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;saveOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;parseCallStack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Output:&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这是一个单例类，核心在于&lt;code&gt;parseCallStack()&lt;/code&gt;方法，通过&lt;code&gt;debug_backtrace()&lt;/code&gt;函数获取日志所在的接口，对于REST接口，得到HTTP请求的路径，对于接口类的方法，得到包含类名的接口名。此外，日志中还会记录当前的用户名，方便定位和复现问题。&lt;/p&gt;</description></item><item><title>Google BBR和锐速在Vultr上的对比</title><link>http://0x3f.org/posts/google-bbr-is-awesome/</link><pubDate>Sun, 23 Apr 2017 23:48:21 +0000</pubDate><guid>http://0x3f.org/posts/google-bbr-is-awesome/</guid><description>&lt;p&gt;BBR比锐速略快，看YouTube的1080p效果差别不大，SSH操作反应改善明显。&lt;/p&gt;
&lt;p&gt;两个都不用的情况：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ speedtest
Retrieving speedtest.net configuration...
Testing from Choopa (xx.xx.xx.xx)...
Retrieving speedtest.net server list...
Selecting best server based on ping...
Hosted by Allied Telesis Capital Corporation (Fussa-shi) [41.04 km]: 88.085 ms
Testing download speed................................................................................
Download: 1.81 Mbit/s
Testing upload speed....................................................................................................
Upload: 7.48 Mbit/s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用锐速的情况：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ speedtest
Retrieving speedtest.net configuration...
Testing from Choopa (xx.xx.xx.xx)...
Retrieving speedtest.net server list...
Selecting best server based on ping...
Hosted by Allied Telesis Capital Corporation (Fussa-shi) [41.04 km]: 96.395 ms
Testing download speed................................................................................
Download: 3.45 Mbit/s
Testing upload speed....................................................................................................
Upload: 4.56 Mbit/s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;用BBR的情况：&lt;/p&gt;</description></item><item><title>Cross-site Request Forgery简介</title><link>http://0x3f.org/posts/introduction-of-cross-site-request-forgery/</link><pubDate>Sun, 23 Apr 2017 20:55:58 +0000</pubDate><guid>http://0x3f.org/posts/introduction-of-cross-site-request-forgery/</guid><description>&lt;h2 id="什么是csrf"&gt;什么是CSRF&lt;/h2&gt;
&lt;p&gt;Cross-site Request Forgery（简称CSRF），意思是跨站请求伪造。原理是利用网站服务器对浏览器的信任，通过一些技术手段欺骗用户的浏览器访问自己曾经认证过的网站，并执行一些危害用户利益的操作。&lt;/p&gt;
&lt;p&gt;例如，假设网站的会话信息保存在cookie中，提现的请求是&lt;code&gt;GET http://www.sample.com/withdraw?toCard=123456&amp;amp;amount=10000&lt;/code&gt;，攻击者在自己的网页中通过img标签、iframe或者AJAX访问这个链接，并诱使用户访问这个网页，如果用户刚刚登录过sample.com，余额就会被转走。&lt;/p&gt;
&lt;h2 id="防止csrf的方法"&gt;防止CSRF的方法&lt;/h2&gt;
&lt;p&gt;CSRF的关键在于用户的鉴权信息保存在cookie中，或攻击者可以拿到它。目前防止CSRF攻击的方法主要有两种：JWT和表单校验token。&lt;/p&gt;
&lt;p&gt;JWT的token通过HTTP请求的header传递，且由于浏览器的跨站限制，钓鱼网页中的JS无法拿到token，从而达到防止CSRF的目的。关于JWT更详细的介绍在「&lt;a href="http://0x3f.org/post/introduction-of-json-web-token/"&gt;JSON Web Token简介&lt;/a&gt;」。&lt;/p&gt;
&lt;p&gt;表单校验token通常是存储在表单的隐藏字段中的一个随机字符串，服务器端通过比对表单提交的token判断请求是否伪造，此时需要注意服务器端的CORS配置，即便在有需要的情况下开放了，也应该严格限制允许的HTTP方法和域，否则，钓鱼网页的JS就可以拿到这个token，从而实现CSRF。&lt;/p&gt;</description></item><item><title>JSON Web Token简介</title><link>http://0x3f.org/posts/introduction-of-json-web-token/</link><pubDate>Sun, 23 Apr 2017 18:29:06 +0000</pubDate><guid>http://0x3f.org/posts/introduction-of-json-web-token/</guid><description>&lt;h2 id="什么是jwt"&gt;什么是JWT？&lt;/h2&gt;
&lt;p&gt;JSON Web Token（简称JWT）是一种token格式，通常用来解决身份认证的问题，和会话（session）作用相同，常用在RESTful API或者OAuth认证上。&lt;/p&gt;
&lt;p&gt;和session相比，JWT有以下优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务器端的开销低&lt;/li&gt;
&lt;li&gt;服务器端扩展方便&lt;/li&gt;
&lt;li&gt;不用专门处理CSRF&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于session的实现方式需要在服务器端存储会话数据，所以当存在大量会话时，服务器端的存储压力会很大，并由此带来扩展上的复杂度（共享session）。而JWT可以把这些数据存储在token里，不需要服务器端存储，优势自然很明显。&lt;/p&gt;
&lt;p&gt;对于CSRF，由于session一般使用cookie实现，所以需要专门处理这个安全隐患。JWT借助HTTP请求的header传递，所以伪造成本更高。&lt;/p&gt;
&lt;h3 id="jwt和bearer-token的关系"&gt;JWT和Bearer Token的关系&lt;/h3&gt;
&lt;p&gt;JWT在使用的时候要在token前面加上字符串「bearer」再填到HTTP请求的header里，这个值就是「Bearer Token」。为什么要这么做？它和JWT是什么关系？&lt;/p&gt;
&lt;p&gt;简单地说，JWT是一种token格式，Bearer Token是一种鉴权方案。&lt;/p&gt;
&lt;p&gt;HTTP的header项「Authorization」是在HTTP 1.0引入的，它的值的格式是&lt;code&gt;类型+token&lt;/code&gt;，支持多种鉴权方案，bearer只是其中的一种。bearer方案中使用的token是JWT格式，这就是它们之间的关系。&lt;/p&gt;
&lt;h2 id="jwt的格式"&gt;JWT的格式&lt;/h2&gt;
&lt;p&gt;JWT是一个用英文点号连接起来的、分成三个部分的字符串：header、payload和signature。&lt;/p&gt;
&lt;h3 id="header"&gt;header&lt;/h3&gt;
&lt;p&gt;header是个base64字符串，解密后是个JSON对象，包含一些元数据。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;&amp;#39;typ&amp;#39;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;JWT&amp;#39;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;&amp;#39;alg&amp;#39;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;HS256&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;「typ」是格式，「alg」是加密方法。&lt;/p&gt;
&lt;h3 id="payload"&gt;payload&lt;/h3&gt;
&lt;p&gt;payload也是个base64字符串，解密后也是个JSON对象，一般包含两种数据：JWT标准数据和自定义数据。&lt;/p&gt;
&lt;p&gt;JWT标准数据常见的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iss：提供方。&lt;/li&gt;
&lt;li&gt;sub：主题，一般是用户ID。&lt;/li&gt;
&lt;li&gt;exp：过期时间。&lt;/li&gt;
&lt;li&gt;iat：创建时间。&lt;/li&gt;
&lt;li&gt;jti：token的唯一标识。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，和session一样，可以把一些自定义的数据存储在payload里。但由于token存储在客户端，所以不应该在这里存储敏感数据。&lt;/p&gt;
&lt;h3 id="signature"&gt;signature&lt;/h3&gt;
&lt;p&gt;signature也是个base64字符串，解密后是个使用header里描述的加密方法针对header和payload加密的字符串。目的是防止这两部分的数据被篡改。&lt;/p&gt;
&lt;h2 id="jwt的使用原则"&gt;JWT的使用原则&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;不存放敏感信息&lt;/li&gt;
&lt;li&gt;保护好私钥&lt;/li&gt;
&lt;li&gt;结合https使用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;都是出于安全角度考虑。token存储在客户端，而且base64可以被解密，所以不能存储敏感数据。如果私钥泄漏，意味著签名可以被随意伪造。使用https可以更好的保护数据，防止中间人攻击。&lt;/p&gt;
&lt;h2 id="jwt相关开发资源"&gt;JWT相关开发资源&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://jwt.io/"&gt;jwt.io&lt;/a&gt;有各种语言的JWT开发资源。&lt;/p&gt;</description></item><item><title>得草根者得天下</title><link>http://0x3f.org/posts/get-the-inferior-class-get-the-throne/</link><pubDate>Fri, 21 Apr 2017 11:05:50 +0000</pubDate><guid>http://0x3f.org/posts/get-the-inferior-class-get-the-throne/</guid><description>&lt;p&gt;国内移动支付是劣质的繁荣，量很大，但是水平低。&lt;/p&gt;
&lt;p&gt;我个人对移动支付偏爱的程度依次是：Apple Pay &amp;gt; 支付宝 &amp;gt; 微信。Apple Pay的体验最好，后两个都多出一个扫码的步骤，微信更是很奇葩地要多一步选卡的操作。&lt;/p&gt;
&lt;p&gt;不过采访过一些人，结果是用微信的最多。&lt;/p&gt;
&lt;p&gt;原因当然是微信的社交切入点带来的普及程度，还有红包的成功，让这个体验最差的东西后来居上。支付宝因为意识到这一点，才不断焦虑地效颦，自乱阵脚，越做越烂。&lt;/p&gt;
&lt;p&gt;我自己平时使用的情况是，能用信用卡支付的一般用支付宝，只能转账的才用微信。而且线下支付还是微信居多。主要原因还是线下的收款方都是小商小贩，大多只会用微信。&lt;/p&gt;
&lt;p&gt;中国正在形成阶层社会，但草根仍是主流，得草根者得天下。&lt;/p&gt;</description></item><item><title>设计RESTful API的几个原则</title><link>http://0x3f.org/posts/some-principles-on-designing-restful-api/</link><pubDate>Fri, 21 Apr 2017 10:07:29 +0000</pubDate><guid>http://0x3f.org/posts/some-principles-on-designing-restful-api/</guid><description>&lt;p&gt;REST不是一项技术，而是一种设计风格。它的核心思想是实现一种清晰明确的语义，用来描述Web操作。包含两个主要因素：HTTP动词和资源地址。&lt;/p&gt;
&lt;h2 id="http动词的使用原则"&gt;HTTP动词的使用原则&lt;/h2&gt;
&lt;p&gt;参与Web操作的HTTP动词主要有GET、POST、DELETE、PUT、HEAD、PATCH。实际上，几乎所有的操作只需GET和POST就可以实现，为什么还要有其它几种呢？目的就是为了实现清晰明确的语义：&lt;code&gt;DELETE /api/v1/post/18&lt;/code&gt;肯定比&lt;code&gt;GET /api/v1/post?id=18&amp;amp;action=delete&lt;/code&gt;更清楚。&lt;/p&gt;
&lt;p&gt;因此HTTP动词使用的重点在于明确语义。例如更新操作，很多文章会说创建资源用POST、修改用PUT，实际上是对REST风格理解不透彻。&lt;/p&gt;
&lt;p&gt;总体上，HTTP动词分为两类：幂等和非幂等。幂等是个数学概念，对于一元操作，如果它作用于任一元素两次以上后所得的结果和第一次相同，就认为它是幂等的。简单地说，如果一个接口，传递同样的实参，多次请求的结果和一次没有不同，就认为它是安全的、幂等的，反之，就是不安全、非幂等的。&lt;/p&gt;
&lt;p&gt;GET、DELETE、PUT、HEAD是幂等操作，POST和PATCH是非幂等操作。因此，修改操作用POST还是PUT，要看操作本身的幂等与否。举个例子，对于修改用户描述的接口，调用任意次得到的结果都是相同的，所以它是幂等的，应该用PUT。而对于修改用户登录积分的操作，假设每次登录加十分，重复调用会导致分数重复增加，这就是不安全、非幂等的，应该用POST。&lt;/p&gt;
&lt;h2 id="资源地址的命名原则"&gt;资源地址的命名原则&lt;/h2&gt;
&lt;p&gt;资源地址是对被操作资源位置的描述，因此应该有以下几个原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全部使用名词&lt;/li&gt;
&lt;li&gt;不使用驼峰风格&lt;/li&gt;
&lt;li&gt;资源名称统一使用复数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于前两个，因为对资源的操作已由HTTP动词表述，资源地址里不应该存在动词，否则会造成语义的混乱。此外，不存在动词也就不需要使用驼峰风格。例如，&lt;code&gt;GET /api/v1/getUser/89&lt;/code&gt;，「get」在语义上就重复了。&lt;/p&gt;
&lt;p&gt;关于资源名称用复数的原则，主要是为了API在风格上的统一，同一种资源用同一个单词表示，单、复数用资源的id表示，URI里有id的就是单数，否则是复数。&lt;/p&gt;
&lt;h2 id="结论"&gt;结论&lt;/h2&gt;
&lt;p&gt;REST是风格而不是技术，出bug的可能性不大，并不是能实现业务逻辑、没有bug就是好代码。风格错了，连REST都不算。&lt;/p&gt;</description></item><item><title>Postman的Pre-request Script和Tests</title><link>http://0x3f.org/posts/pre-request-script-and-tests-in-postman/</link><pubDate>Wed, 19 Apr 2017 17:05:55 +0000</pubDate><guid>http://0x3f.org/posts/pre-request-script-and-tests-in-postman/</guid><description>&lt;p&gt;Pre-request Script和Tests都是Javascript代码块。前者在请求发起前执行，通常用来生成请求数据，例如对用户注册接口随机生成用户名。后者在请求结束后执行，通常用来测试和处理返回值。&lt;/p&gt;
&lt;p&gt;以下是随机生成用户名的Pre-request Script：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;postman&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;random_username&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;测试用户&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;产生的值存储在环境变量里，表单里直接引用环境变量即可。&lt;/p&gt;
&lt;p&gt;对于REST接口普遍使用的JWT，可以在登录接口的Tests里直接把返回的token更新到环境变量里，这样其它接口直接引用这个环境变量即可：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;token is returned&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;string&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;postman&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;token&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>用Raspberry Pi实现音频Airplay</title><link>http://0x3f.org/posts/implement-airplay-with-raspberry-pi/</link><pubDate>Mon, 17 Apr 2017 10:19:51 +0000</pubDate><guid>http://0x3f.org/posts/implement-airplay-with-raspberry-pi/</guid><description>&lt;p&gt;&lt;img src="http://ww1.sinaimg.cn/large/006tKfTcly1fepi05fa8ej31kw1kwx6q.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;用树莓派做音频airplay效果不错，老书架音箱又可以用起来了。&lt;/p&gt;
&lt;p&gt;实现方式是shairplay-sync，利用HDMI转VGA线上的3.5mm音频输出孔，因为我的树莓派2B的3.5mm音视频输出口没有合适的转接头。&lt;/p&gt;
&lt;p&gt;我用的是Arch Linux ARM，需要手动开启HDMI输出。修改&lt;code&gt;/boot/config.txt&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;hdmi_force_hotplug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;hdmi_drive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;config_hdmi_boost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;dtparam&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;audio=on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;重启后，用alsamixer把树莓派音量调整到最大值。&lt;/p&gt;
&lt;p&gt;AUR里没有针对ARM的shairplay-sync，需要手动编译：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/mikebrady/shairport-sync.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 生成configure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;autoreconf -i -f
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 针对systemd编译&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./configure --sysconfdir&lt;span class="o"&gt;=&lt;/span&gt;/etc --with-alsa --with-avahi --with-ssl&lt;span class="o"&gt;=&lt;/span&gt;openssl --with-metadata --with-soxr --with-systemd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 如果shairport-sync用户不存在，新增用户和用户组&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getent group shairport-sync &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; sudo groupadd -r shairport-sync &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getent passwd shairport-sync &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&amp;gt; /dev/null &lt;span class="o"&gt;||&lt;/span&gt; sudo useradd -r -M -g shairport-sync -s /usr/bin/nologin -G audio shairport-sync &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;airplay默认的服务名和树莓派的hostname一致，可以到&lt;code&gt;/etc/shairport-sync.conf&lt;/code&gt;里修改：&lt;/p&gt;</description></item><item><title>编写接口文档的最佳实践</title><link>http://0x3f.org/posts/the-best-practice-of-writing-api-documents/</link><pubDate>Mon, 10 Apr 2017 16:36:27 +0000</pubDate><guid>http://0x3f.org/posts/the-best-practice-of-writing-api-documents/</guid><description>&lt;p&gt;&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx9m0n7jj30rr0m8gpa.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;传统的做法是用office写接口文档，这种方式的缺点很多：&lt;/p&gt;
&lt;h3 id="格式混乱"&gt;格式混乱&lt;/h3&gt;
&lt;p&gt;事实上，所有的传统富文本文档都存在这个问题，富文本的跨平台兼容性很差，很容易造成格式错乱。&lt;/p&gt;
&lt;h3 id="版本管理困难"&gt;版本管理困难&lt;/h3&gt;
&lt;p&gt;依赖文件系统管理文档是很落后的做法，很难保证手头的文档是最新的版本。&lt;/p&gt;
&lt;h3 id="兼容性差"&gt;兼容性差&lt;/h3&gt;
&lt;p&gt;不是所有人都用windows。&lt;/p&gt;
&lt;h3 id="低效"&gt;低效&lt;/h3&gt;
&lt;p&gt;对效率的负面影响很大程度上已经包含在前面几项里。此外，编辑工具的臃肿、编辑内容的同时还要调整样式、缺少全文检索等，也是导致效率下降的原因。&lt;/p&gt;
&lt;h2 id="理想情况"&gt;理想情况&lt;/h2&gt;
&lt;p&gt;理想的接口文档应该有以下特征：&lt;/p&gt;
&lt;h3 id="方便创作"&gt;方便创作&lt;/h3&gt;
&lt;p&gt;文档编辑最重要的是文档的内容，而不是编辑操作本身。所以编写文档的过程应该是简单快捷的，而且最好不需要额外的学习成本。&lt;/p&gt;
&lt;h3 id="排版简洁规范"&gt;排版简洁规范&lt;/h3&gt;
&lt;p&gt;技术文档的排版，简洁规范是最重要的，花哨的排版会降低效率。&lt;/p&gt;
&lt;h3 id="方便查阅"&gt;方便查阅&lt;/h3&gt;
&lt;p&gt;应该有目录或者大纲视图，并且可以方便地全文检索。&lt;/p&gt;
&lt;h3 id="在线协作"&gt;在线协作&lt;/h3&gt;
&lt;p&gt;传统的离线文档不方便协作。&lt;/p&gt;
&lt;h3 id="多端兼容"&gt;多端兼容&lt;/h3&gt;
&lt;p&gt;允许在大多数常见平台编辑和使用文档。&lt;/p&gt;
&lt;h3 id="版本管理"&gt;版本管理&lt;/h3&gt;
&lt;p&gt;可以查看什么人在什么时间改了哪些内容。&lt;/p&gt;
&lt;h3 id="交互式文档"&gt;交互式文档&lt;/h3&gt;
&lt;p&gt;所见即所得。可以修改参数、发送请求并查看接口返回值。&lt;/p&gt;
&lt;h3 id="可订阅"&gt;可订阅&lt;/h3&gt;
&lt;p&gt;可以给接口打标签。用户可以订阅任意标签下的接口变更，也可以针对接口订阅。&lt;/p&gt;
&lt;h3 id="自动生成"&gt;自动生成&lt;/h3&gt;
&lt;p&gt;如果代码的可读性足够好，何必浪费时间写文档？或者至少可以自动生成。&lt;/p&gt;
&lt;h2 id="当前实践"&gt;当前实践&lt;/h2&gt;
&lt;p&gt;理想很丰满，但是目前还没有能满足以上所有需求的解决方案。权衡之下，markdown和wiki是目前比较合适的方案。&lt;/p&gt;
&lt;h3 id="markdown"&gt;markdown&lt;/h3&gt;
&lt;p&gt;用markdown写文档有以下特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;适合单文档形式&lt;/li&gt;
&lt;li&gt;主流git托管平台都支持&lt;/li&gt;
&lt;li&gt;适合个人创作&lt;/li&gt;
&lt;li&gt;适合小型项目、需要移交开发成果的项目&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面是用markdown写的接口文档的例子：
&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvx9zyd4tj30h81qbn05.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;主流markdown编辑器在转换过程中会为标题添加锚点，利用这个特性可以实现从接口列表跳转到接口详情。&lt;/p&gt;
&lt;h4 id="最佳工具"&gt;最佳工具&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://www.zybuluo.com"&gt;Cmd Markdown&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;美观&lt;/li&gt;
&lt;li&gt;跨平台&lt;/li&gt;
&lt;li&gt;编辑操作支持Vim模式&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="wiki"&gt;wiki&lt;/h3&gt;
&lt;p&gt;用wiki写文档有这些特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方便多层级文档&lt;/li&gt;
&lt;li&gt;需要自己搭建平台&lt;/li&gt;
&lt;li&gt;适合团队创作&lt;/li&gt;
&lt;li&gt;适合长期、大型项目&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="最佳工具-1"&gt;最佳工具&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://www.dokuwiki.org"&gt;dokuwiki&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;刚刚好&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="结论"&gt;结论&lt;/h2&gt;
&lt;p&gt;综上，小型的、托管在主流git平台的项目适合用markdown，公司级项目用wiki更好。但这还达不到理想的标准，需要继续探索更好的解决方案。&lt;/p&gt;</description></item><item><title>一次对Workflow不完全成功的抓包过程</title><link>http://0x3f.org/posts/a-failed-attempt-to-capture-workflow-requests/</link><pubDate>Tue, 04 Apr 2017 20:19:52 +0000</pubDate><guid>http://0x3f.org/posts/a-failed-attempt-to-capture-workflow-requests/</guid><description>&lt;p&gt;一个workflow对https链接的请求总是失败，而同样的接口在postman里是成功的。所以想对比一下两个请求的差异。&lt;/p&gt;
&lt;p&gt;尝试了两种抓包方式，都不成功。一种是用中间人攻击的原理，用的是mitmproxy，类似的还有charles、fiddler等。另一种是从网卡直接抓取，用的是wireshark。&lt;/p&gt;
&lt;p&gt;第一种情况，虽然在iOS里安装并信任了mitmproxy的伪证书、safari里也是可以正常访问https链接的，但在workflow里仍然不认。&lt;/p&gt;
&lt;p&gt;第二种情况，wireshark支持两种解密TLS包的方式：一是使用https服务的私钥，二是用浏览器输出的「SSLKEYLOGFILE」。这里需要用第二种。但是这种方式只对本机发送的请求有效，而且在实际操作中还发现有时候本机也解密不了。&lt;/p&gt;
&lt;p&gt;最后只能采用临时方案，把https链接改成http，然后用mitmproxy抓取，虽然请求是失败的，但是可以拿到请求本身的数据。&lt;/p&gt;</description></item><item><title>玉渊潭的樱花</title><link>http://0x3f.org/posts/sakura-in-yuyuantan-park/</link><pubDate>Tue, 04 Apr 2017 10:23:43 +0000</pubDate><guid>http://0x3f.org/posts/sakura-in-yuyuantan-park/</guid><description>&lt;p&gt;有一小片樱花集中的地方还是不错的，风来，落英缤纷。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230825112714000-c4e70bbe36c8a50c4f0765567ea065b2.avif" alt="2023-08-25-11-27-14-2FC4E1F6-5DDF-4F5A-B952-B12F45516E5B_1_105_c"&gt;&lt;/p&gt;</description></item><item><title>迄今最好的发送网页到 Kindle 的快捷指令</title><link>http://0x3f.org/posts/send-to-kindle-with-shortcut/</link><pubDate>Thu, 30 Mar 2017 11:12:02 +0000</pubDate><guid>http://0x3f.org/posts/send-to-kindle-with-shortcut/</guid><description>&lt;p&gt;转换成 PDF 和 FiveFilters 都不完美， &lt;code&gt;send.reabble.cn&lt;/code&gt; 是迄今最好的解决方案，所以写了这个快捷指令：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.icloud.com/shortcuts/4570dd39486c4d3fb35ee0bb1254e324"&gt;Send to Kindle&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参照 Reabble 的说明做相关配置。&lt;/li&gt;
&lt;li&gt;用 Kindle 接收邮箱创建一个联系人，并在快捷指令里选择他。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2023-04-20&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;优化了提示信息。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2021-10-05&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用新的 send.reabble.cn 替换原 com 域名，修复发送失败的问题。&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>Shadowrocket下优酷无法播放的解决办法</title><link>http://0x3f.org/posts/how-to-play-youku-under-shadowrocket/</link><pubDate>Sun, 26 Mar 2017 00:03:10 +0000</pubDate><guid>http://0x3f.org/posts/how-to-play-youku-under-shadowrocket/</guid><description>&lt;p&gt;导入&lt;a href="http://www.abclite.cn/1995.html"&gt;这里&lt;/a&gt;提供的配置文件。&lt;/p&gt;</description></item><item><title>自动探测RSS地址的workflow</title><link>http://0x3f.org/posts/find-rss-with-workflow/</link><pubDate>Fri, 24 Mar 2017 21:09:13 +0000</pubDate><guid>http://0x3f.org/posts/find-rss-with-workflow/</guid><description>&lt;p&gt;RSS真是没落了，很多网站都没有明确输出Feed地址，每次想订阅都要浪费不少时间，所以写了这个&lt;a href="https://workflow.is/workflows/7f02a38a6c21414a96a4f96600c94662"&gt;Workflow&lt;/a&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;列出页面中所有的Feed地址，点击后复制到剪贴板&lt;/li&gt;
&lt;li&gt;如果页面中的Feed地址是相对地址，自动转换为绝对地址&lt;/li&gt;
&lt;li&gt;如果页面中没有Feed地址，列出常见的几种地址，并侦测被点选的地址，侦测成功后自动复制到剪贴板&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src="https://ww1.sinaimg.cn/large/006tNc79ly1fdy95stcokj30ih0wugnk.jpg" alt=""&gt;
&lt;img src="https://ww3.sinaimg.cn/large/006tNc79ly1fdy95w6sncj30ih0wumyy.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>用 Keyboard Maestro 自动登录 Mac App Store</title><link>http://0x3f.org/posts/auto-login-mas-with-keyboard-maestro/</link><pubDate>Tue, 21 Mar 2017 22:51:32 +0000</pubDate><guid>http://0x3f.org/posts/auto-login-mas-with-keyboard-maestro/</guid><description>&lt;p&gt;按以下步骤配置：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在 Keychain 里创建一个密码项，填上 Apple ID 和密码。&lt;/li&gt;
&lt;li&gt;下载 &lt;a href="http://0x3f.org/attachments/login_mas.kmmacros"&gt;login_mas.kmmacros&lt;/a&gt; 并导入。&lt;/li&gt;
&lt;li&gt;将 &lt;code&gt;YOUR@EMAIL.COM&lt;/code&gt; 改成自己的 Apple ID 。&lt;/li&gt;
&lt;li&gt;将 &lt;code&gt;YOUR KEYCHAIN PASSWORD NAME&lt;/code&gt; 改成 Keychain 里密码项的名称。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20230709212957000-7a199d439d52f53900768adffdddf76c.avif" alt="2023-07-09-21-29-57-login_mas_with_keyboard_maestro"&gt;&lt;/p&gt;</description></item><item><title>MacOS中切换输入法的最佳实践</title><link>http://0x3f.org/posts/the-best-practice-of-switching-input-methods-in-macos/</link><pubDate>Mon, 20 Mar 2017 14:25:00 +0000</pubDate><guid>http://0x3f.org/posts/the-best-practice-of-switching-input-methods-in-macos/</guid><description>&lt;p&gt;原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一键切换&lt;/li&gt;
&lt;li&gt;可以对特定应用设定初始输入状态&lt;/li&gt;
&lt;li&gt;可以方便地确认当前输入状态&lt;/li&gt;
&lt;li&gt;兼容外接键盘&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;思路：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用Karabiner Elements把右Shift修改成F19，在系统里设置用F19切换输入法&lt;/li&gt;
&lt;li&gt;用isHUD显示输入法状态&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/auto-switch-keyboard-layouts-in-macos/"&gt;用Keyboard Maestro自动切换键盘布局&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Karabiner Elements会使系统的键盘布局失效，且不能对不同的键盘使用不同的布局，所以只有用Keyboard Maestro自动切换。&lt;/p&gt;
&lt;p&gt;isHUD只在切换输入法时有效，理想情况是用Caps Lock键灯表示输入状态，不过目前没找到可用的解决办法。&lt;/p&gt;
&lt;p&gt;鼠须管可以对不同的应用设置初始输入状态，但只是在切换输入法后，例如对于Alfred，如果上次鼠须管处于中文输入状态，再次打开输入框的时候不会变成英文状态，因此需要在Alfred中设置初始输入法为英文。&lt;/p&gt;</description></item><item><title>MacOS下自动切换Karabiner Elements配置</title><link>http://0x3f.org/posts/auto-switch-keyboard-layouts-in-macos/</link><pubDate>Mon, 20 Mar 2017 13:14:18 +0000</pubDate><guid>http://0x3f.org/posts/auto-switch-keyboard-layouts-in-macos/</guid><description>&lt;p&gt;Karabiner Elements不支持对不同的键盘自动使用不同的配置，所以本文通过监听USB键盘插拔事件实现自动切换。&lt;/p&gt;
&lt;h2 id="依赖"&gt;依赖：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Keyboard Maestro&lt;/li&gt;
&lt;li&gt;php&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="脚本"&gt;脚本&lt;/h2&gt;
&lt;p&gt;Karabiner Elements会监听配置文件&lt;code&gt;~/.config/karabiner/karabiner.json&lt;/code&gt;，如果有变动，会自动重新加载。&lt;/p&gt;
&lt;p&gt;切换配置的脚本在&lt;a href="https://github.com/xbot/shell/blob/master/karabiner-elements-profile-switcher.php"&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="keyboard-maestro"&gt;Keyboard Maestro&lt;/h2&gt;
&lt;p&gt;键盘插入事件：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ww3.sinaimg.cn/large/006tNc79ly1fdt8iy3ydmj30cq0b6q3z.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;键盘拔出事件：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ww2.sinaimg.cn/large/006tNc79ly1fdt8jz1aspj30cn0b1my6.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>尝新，明前碧螺春</title><link>http://0x3f.org/posts/try-biluochun-2017/</link><pubDate>Sun, 19 Mar 2017 18:19:40 +0000</pubDate><guid>http://0x3f.org/posts/try-biluochun-2017/</guid><description>&lt;p&gt;&lt;img src="https://ww2.sinaimg.cn/large/006tNc79ly1fdsbari7pij30sg0sgk0d.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;近年明前都要试一种新茶，今年是碧螺春。&lt;/p&gt;
&lt;p&gt;不觉得有什么特别的地方，就是不耐泡。&lt;/p&gt;</description></item><item><title>一碗酸汤面</title><link>http://0x3f.org/posts/noodles-in-acid-soup/</link><pubDate>Sun, 19 Mar 2017 18:12:36 +0000</pubDate><guid>http://0x3f.org/posts/noodles-in-acid-soup/</guid><description>&lt;p&gt;&lt;img src="https://ww4.sinaimg.cn/large/006tNc79ly1fdsballmi5j30sg0sgdnh.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;继续清淡。&lt;/p&gt;
&lt;p&gt;依赖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;挂面&lt;/li&gt;
&lt;li&gt;小葱&lt;/li&gt;
&lt;li&gt;香油、盐、陈醋、生抽&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;小葱切丁，碗里放醋、生抽、盐&lt;/li&gt;
&lt;li&gt;水烧开，下面，点一次水&lt;/li&gt;
&lt;li&gt;捞面，浇汤&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>沙发椅，让阅读更有趣</title><link>http://0x3f.org/posts/my-new-sofa-chair/</link><pubDate>Sat, 18 Mar 2017 22:48:35 +0000</pubDate><guid>http://0x3f.org/posts/my-new-sofa-chair/</guid><description>&lt;p&gt;&lt;img src="https://ww2.sinaimg.cn/large/006tNc79ly1fdrdpa2eu2j30sg0sg7cu.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;心水沙发椅很久了，终于拔草。&lt;/p&gt;
&lt;p&gt;因为喜欢极简，之前一直用著一张双人小沙发，但是不够舒适，也不便移动。后来坐过一间餐厅的沙发椅感觉包覆感很好，就想著换一下，于是出掉了沙发，准备入一把伊姆斯椅，偶然看到现在这把，瞬间庆幸没有草率地买前者。&lt;/p&gt;
&lt;p&gt;在阳台上阅读变得更有趣了，这椅子和小抱枕很搭（&lt;em&gt;不是照片中这个&lt;/em&gt;）。&lt;/p&gt;</description></item><item><title>一碗阳春面</title><link>http://0x3f.org/posts/noodles-in-a-simple-sauce/</link><pubDate>Sat, 18 Mar 2017 20:49:07 +0000</pubDate><guid>http://0x3f.org/posts/noodles-in-a-simple-sauce/</guid><description>&lt;p&gt;&lt;img src="https://ww2.sinaimg.cn/large/006tNbRwly1fdra76g0i1j30sg0sgjy4.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;想吃点清淡的。&lt;/p&gt;
&lt;p&gt;依赖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;挂面&lt;/li&gt;
&lt;li&gt;小葱&lt;/li&gt;
&lt;li&gt;香油、盐&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;小葱切丁&lt;/li&gt;
&lt;li&gt;水烧开，下面，点一次水&lt;/li&gt;
&lt;li&gt;捞面沥水，撒葱花、盐，浇开水&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>干锅土豆片</title><link>http://0x3f.org/posts/new-dish-dry-pot-potato/</link><pubDate>Thu, 16 Mar 2017 11:11:59 +0000</pubDate><guid>http://0x3f.org/posts/new-dish-dry-pot-potato/</guid><description>&lt;p&gt;&lt;img src="https://ww1.sinaimg.cn/large/006tNbRwly1fdoid7q73mj30sg0sgwnf.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;没有平底锅和夹子是硬伤啊。&lt;/p&gt;
&lt;p&gt;依赖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;土豆&lt;/li&gt;
&lt;li&gt;黄豆酱、干辣椒、花椒、姜、蒜、油&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;土豆切片，干辣椒掰两半，姜切丝，蒜切块&lt;/li&gt;
&lt;li&gt;土豆片放沸水30秒，煎黄取出&lt;/li&gt;
&lt;li&gt;放油、黄豆酱、干辣椒、花椒、姜、蒜，炒香&lt;/li&gt;
&lt;li&gt;放土豆片，翻炒，太干的话放一点水&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>鼠须管实现简繁转换的方法</title><link>http://0x3f.org/posts/switch-cn-tw-in-rime/</link><pubDate>Sat, 11 Mar 2017 23:42:11 +0000</pubDate><guid>http://0x3f.org/posts/switch-cn-tw-in-rime/</guid><description>&lt;p&gt;鼠须管默认输出繁体，可以通过自带的过滤器转换成简体。这样做是科学的，因为繁体的异体字较多，从简转繁容易转错。&lt;/p&gt;
&lt;p&gt;对于只有简体的码表，可以转换成繁体，再通过过滤器转简体，但是会导致在简体状态下无法自造词。所以最好的办法是给繁体单独配一个码表。&lt;/p&gt;
&lt;p&gt;步骤为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;复制简体码表的schema.yaml和dict.yaml文件&lt;/li&gt;
&lt;li&gt;修改两个yaml文件的名称&lt;/li&gt;
&lt;li&gt;文件内容中和文件名对应的内容也都改为和新文件名一致&lt;/li&gt;
&lt;li&gt;修改schema.yaml中输入法的名称，使之和简体码表区分开&lt;/li&gt;
&lt;li&gt;转换dict.yaml中的内容到繁体&lt;/li&gt;
&lt;li&gt;重新部署&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果需要给繁体码表增加临时输出简体的功能，方法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 在码表的schema.yaml中&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# switches下增加&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;simplification&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;states&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;汉字, 汉字 ]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# engine下增加&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;simplifier&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;uniquifier&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;#key_binder下增加&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- {&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;when: always, accept: Control+Shift+4, toggle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;simplification }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- {&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;when: always, accept: Control+Shift+dollar, toggle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;simplification }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>干锅菜花</title><link>http://0x3f.org/posts/dry-pot-cauliflower/</link><pubDate>Wed, 08 Mar 2017 20:55:54 +0000</pubDate><guid>http://0x3f.org/posts/dry-pot-cauliflower/</guid><description>&lt;p&gt;&lt;img src="https://ww1.sinaimg.cn/large/006tNbRwly1fdfq6e4b0qj30sg0sg11s.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;去年学的。&lt;/p&gt;
&lt;p&gt;依赖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;菜花&lt;/li&gt;
&lt;li&gt;姜、干辣椒、花椒&lt;/li&gt;
&lt;li&gt;黄豆酱、生抽、料酒、油&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;菜花泡盐水&lt;/li&gt;
&lt;li&gt;放油、姜、花椒、干辣椒、豆瓣酱，炒香&lt;/li&gt;
&lt;li&gt;放菜花，翻炒入味&lt;/li&gt;
&lt;li&gt;放生抽、料酒&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>胡萝卜炒杏鲍菇</title><link>http://0x3f.org/posts/new-dish-mushroom-carrot-pepper/</link><pubDate>Tue, 07 Mar 2017 21:10:05 +0000</pubDate><guid>http://0x3f.org/posts/new-dish-mushroom-carrot-pepper/</guid><description>&lt;p&gt;&lt;img src="https://ww2.sinaimg.cn/large/006tNbRwly1fdekxg6n3nj30sg0sgn60.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;去年学的，今天忘买蒜了，也挺好吃的。&lt;/p&gt;
&lt;p&gt;依赖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;杏鲍菇&lt;/li&gt;
&lt;li&gt;胡萝卜&lt;/li&gt;
&lt;li&gt;青椒&lt;/li&gt;
&lt;li&gt;姜、蒜、黑胡椒粉、淀粉、生抽、盐、油&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;杏鲍菇、胡萝卜、蒜切片，青椒、姜切丝，淀粉勾芡&lt;/li&gt;
&lt;li&gt;放油、蒜、姜，油热后放胡萝卜，炒至半熟&lt;/li&gt;
&lt;li&gt;放杏鲍菇，炒软&lt;/li&gt;
&lt;li&gt;芡汁入锅，放黑胡椒粉、生抽、盐&lt;/li&gt;
&lt;li&gt;放青椒&lt;/li&gt;
&lt;li&gt;炒至色泽出现、汤汁量合适出锅&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>加速Homebrew</title><link>http://0x3f.org/posts/speed-up-homebew/</link><pubDate>Mon, 06 Mar 2017 23:14:02 +0000</pubDate><guid>http://0x3f.org/posts/speed-up-homebew/</guid><description>&lt;p&gt;两个方法：走代理和使用国内镜像。镜像有同步时间差，而且遇到国外资源还是慢。&lt;/p&gt;
&lt;p&gt;homebrew用curl下载，用proxychains和环境变量http_proxy都没用，需要在&lt;code&gt;~/.curlrc&lt;/code&gt;里配置：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;socks5 = &amp;#34;127.0.0.1:1080&amp;#34;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>CORS：另一种前端跨域请求方式</title><link>http://0x3f.org/posts/cors/</link><pubDate>Mon, 27 Feb 2017 17:07:17 +0000</pubDate><guid>http://0x3f.org/posts/cors/</guid><description>&lt;p&gt;CORS的全称是「Cross-Origin Resource Sharing」，即跨域资源共享。&lt;/p&gt;
&lt;p&gt;CORS是比JSONP更强大的前端跨域请求的实现方式。JSONP只支持GET请求，而CORS支持更多种类。JSONP的优势是支持老版本的浏览器。&lt;/p&gt;
&lt;p&gt;实现CORS需要浏览器和服务器同时支持，主流框架有实现CORS的中间件，如：&lt;a href="https://github.com/barryvdh/laravel-cors"&gt;laravel-cors&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;具体参考：http://www.ruanyifeng.com/blog/2016/04/cors.html&lt;/p&gt;</description></item><item><title>怎样在Vim中删除引号文本对象</title><link>http://0x3f.org/posts/how-to-delete-quoted-text-object-in-vim/</link><pubDate>Sat, 25 Feb 2017 19:33:18 +0000</pubDate><guid>http://0x3f.org/posts/how-to-delete-quoted-text-object-in-vim/</guid><description>&lt;p&gt;假设有这样一段代码（光标在「|」位置）：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$title = &amp;ldquo;Article:|&amp;rdquo; . $realTitle;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;要删除引号及其内容，并进入插入模式准备输入其它内容。&lt;/p&gt;
&lt;p&gt;如果执行&lt;code&gt;ca&amp;quot;&lt;/code&gt;，会得到如下的结果：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$title = |. $realTitle;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;连引号旁边的空格也删除了。&lt;/p&gt;
&lt;p&gt;如果不想删除空格，可以用&lt;code&gt;c2i&amp;quot;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;参考：&lt;a href="https://www.reddit.com/r/vim/comments/5v4gm5/is_it_possible_to_exclude_surrounding_whitespace/"&gt;Is it possible to exclude surrounding whitespace from the word-object &lt;code&gt;a&amp;quot;&lt;/code&gt;?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>技术团队的两个最佳实践</title><link>http://0x3f.org/posts/the-best-practices-of-developing/</link><pubDate>Fri, 24 Feb 2017 13:27:57 +0000</pubDate><guid>http://0x3f.org/posts/the-best-practices-of-developing/</guid><description>&lt;p&gt;在以往的开发和管理中遇到很多问题，以至于我对理想中的技术团队有了一些想法。其中有两点经过实践证明有很强的可操作性，值得拿出来讨论一下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;能用规则解决的问题就不要靠人解决&lt;/li&gt;
&lt;li&gt;能用机器完成的任务就不要用人处理&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两点都反映了我的一个妄念，就是相信规则和机器，不相信人。人是最不靠谱的生产者，你永远无法保证团队中的每个人都处于很好的状态、拥有相近的技术水平和情商，这也是为什么我不觉得结对编程有什么可操作性。但如果有简单可行的规则，用来规范开发过程中的行为，那么解决开发过程中的冲突就不需要人为地和稀泥，生产效率也会得到提升。此外，机器最适合用来做重复性的任务，很多花大量的人力、物力、时间都没做得很好的事，交给机器来做恰恰是最好的解决办法。&lt;/p&gt;
&lt;p&gt;这些以往都只是我自己的想法，虽然在团队里有过很好的实践效果，但是并不指望和别人有所共鸣。国内的技术团队大多靠堆人、堆时间，很少有团队会把健康的世界观和可操作的方法论放在重要的位置，技术和技术从业者都是刍狗。当然这也无可厚非，毕竟先要解决生存问题，在模式创新为主的国内互联网行业，更新换代如此之快，产品早一天上线就多一分生存的可能。但是有没有可能既解决生存问题，又做出一个有荣誉感的团队呢？世间安得双全法，这是个值得持续讨论的问题。&lt;/p&gt;
&lt;p&gt;最近和别人聊天，竟然听到相同的想法，在具体的方法论上还得到很多补充。&lt;/p&gt;
&lt;p&gt;对于第一点。一个项目按业务线划分开发组、按功能模块划分开发任务本来是个很好的模式，但是接口的对接往往会有很多问题，例如术语使用的不严谨导致高昂的沟通成本、问题处理方法的不规范导致扯皮、冲突和低效。&lt;/p&gt;
&lt;p&gt;在我的团队里，用wiki维护著一套术语词典，开发过程中所有的文档、沟通都必须使用既定的用语，例如「退单」包括「退款单」和「退货单」，这三个术语分别表示不同而精确的概念，如果因为自己造词产生歧义或错用术语导致开发事故，责任是清楚的，问责对象也没有怨言。让有责任的人承担责任，比和稀泥对解决问题更有利。&lt;/p&gt;
&lt;p&gt;再比如，问题在流转过程中很容易出现接口人之间的扯皮甚至冲突，问题的根源并不是别人说你的代码有问题导致你不爽，而是别人做得不够专业让你觉得对方不负责任。在我的团队里，大家约定处理问题的规则是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;谁接手，谁处理&lt;/li&gt;
&lt;li&gt;转交问题时必须提供四项信息：复现问题的环境、完整的接口名、传递的实参和返回结果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;首先当一个问题被反馈过来的时候，分配人会有一个初步的判断，指派给谁，谁处理，不能踢皮球。处理人如果界定问题发生在别人的接口里，应该把上述四项信息连同问题移交给相关责任人。这样做的好处是，一来可以避免误判给别人造成不必要的麻烦，二来让下游接口人可以马上复现并解决问题，而无须考虑上游的业务逻辑。这个规则的效果很好，团队里从来没有因为接口问题出现不愉快。&lt;/p&gt;
&lt;p&gt;对于第二点。代码质量是日常开发中最让人头疼的问题之一，出现频率高而且代价昂贵。不管是靠开发人员的经验，还是测试人员的工作，都对人的依赖很大，既不稳定又低效。以下这些方法能很好地解决这样的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用Git，先进的生产关系需要更好的生产资料才能带来更高的生产力&lt;/li&gt;
&lt;li&gt;提交代码时自动检查语法错误和代码规范&lt;/li&gt;
&lt;li&gt;高覆盖率、自动化的单元测试&lt;/li&gt;
&lt;li&gt;用模拟工具给单元测试供给测试数据&lt;/li&gt;
&lt;li&gt;用脚本测试网页交互&lt;/li&gt;
&lt;li&gt;用脚本给网页截图，用图片diff工具比较某次修改给网页带来的变化&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Git的衍合</title><link>http://0x3f.org/posts/git-rebase/</link><pubDate>Wed, 22 Feb 2017 18:44:37 +0000</pubDate><guid>http://0x3f.org/posts/git-rebase/</guid><description>&lt;p&gt;合并分支有两种方式，merge和rebase。merge是根据三方合并的差异，创建一个新的提交。rebase是将上游分支的各个提交在比较差异后在下游分支上重演一遍。&lt;/p&gt;
&lt;p&gt;rebase适合对没有推送到远程的提交对象做合并，这样可以保持一个整洁的提交历史。若对已推送的提交对象使用rebase，可能导致其它已经拉取并创建了新的提交的人不得不重新合并，进而导致提交历史变得很混乱。&lt;/p&gt;
&lt;p&gt;基本的rebase：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase master unstable
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge unstable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;复杂的情况：存在三个分支，unstable基于master的某个提交创建，feature基于unstable的某个提交创建，要把feature合并到master而不合并unstable。更多分支时方法也一样。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rebase --onto master unstable feature
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git merge feature
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;rebase过程中如果存在冲突，合并后用&lt;code&gt;git add&lt;/code&gt;标记已解决，再用&lt;code&gt;git rebase --continue&lt;/code&gt;继续。如果解决冲突后仍然不能继续，可能是当前补丁的内容在下游分支已存在，可以用&lt;code&gt;git rebase --skip&lt;/code&gt;跳过。&lt;/p&gt;</description></item><item><title>在Vim中格式化Javascript、HTML和CSS</title><link>http://0x3f.org/posts/vim-js-beautify/</link><pubDate>Tue, 21 Feb 2017 14:58:08 +0000</pubDate><guid>http://0x3f.org/posts/vim-js-beautify/</guid><description>&lt;h2 id="依赖"&gt;依赖&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/maksimr/vim-jsbeautify"&gt;vim-jsbeautify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/beautify-web/js-beautify"&gt;js-beautify&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;js-beautify的安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm -g install js-beautify
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 或&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install jsbeautifier
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="配置快捷键"&gt;配置快捷键&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;vmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;jsb&lt;/span&gt; :&lt;span class="s1"&gt;&amp;#39;&amp;lt;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;beautify&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;javascript&lt;/span&gt; &lt;span class="nx"&gt;noremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;jsb&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;JsBeautify&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;noremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;htmlb&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;HtmlBeautify&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt; &lt;span class="nx"&gt;noremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;cssb&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;CSSBeautify&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Vim 查找与替换的最佳实践</title><link>http://0x3f.org/posts/the-best-practice-of-searching-in-vim/</link><pubDate>Sun, 19 Feb 2017 20:37:18 +0000</pubDate><guid>http://0x3f.org/posts/the-best-practice-of-searching-in-vim/</guid><description>&lt;h2 id="更新"&gt;更新&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;日期&lt;/th&gt;
&lt;th&gt;更新内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2022-03-16&lt;/td&gt;
&lt;td&gt;更新 80% 的内容。包含这几年所有的配置上的更新，并且把 ag 换成了 rg 。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2017-02-19&lt;/td&gt;
&lt;td&gt;第一版。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;多文件搜索和替换&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 PCRE 正则表达式在工作目录下递归搜索&lt;/li&gt;
&lt;li&gt;将选定文本自动转换成正则表达式&lt;/li&gt;
&lt;li&gt;有较高的搜索速度&lt;/li&gt;
&lt;li&gt;对搜索结果做替换&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当前 buffer 内的搜索和替换&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一键将选定文本自动转换成正则表达式并执行搜索或替换&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="依赖"&gt;依赖&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/wincent/ferret"&gt;Ferret&lt;/a&gt;：实现对搜索和替换操作的封装。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BurntSushi/ripgrep"&gt;ripgrep&lt;/a&gt;：搜索工具，速度快。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工具和方法"&gt;工具和方法&lt;/h2&gt;
&lt;h3 id="ferret"&gt;Ferret&lt;/h3&gt;
&lt;p&gt;Ferret 是我用过的 vim 搜索扩展里最接近理想的一个，最大的优点是不用引号包裹搜索内容，且较大程度地支持 PCRE 正则表达式。&lt;/p&gt;
&lt;p&gt;EasyGrep 的缺点是正则表达式必须是 shellescape() 过的，手写不方便，也不直观。Ferret 在底层做了 shellescape() ，所以比 EasyGrep 简单一些。&lt;del&gt;不过 Ferret 对反斜杠的处理仍然不直观，例如搜索&lt;code&gt;App\Link&lt;/code&gt;，正则表达式是&lt;code&gt;App\\Link&lt;/code&gt;，而Ferret里只能用&lt;code&gt;App\\\\Link&lt;/code&gt;。原因是从输入到执行，存在著三层转义：Vim命令行、Shell、grep/ag。所以对于EasyGrep，要搜索一个&lt;code&gt;\&lt;/code&gt;，必须输入&lt;code&gt;\\\\\\\\&lt;/code&gt;。对于Ferret，由于底层做了shellescape()，只需要两层转义，即&lt;code&gt;\\\\&lt;/code&gt;。当然这样也不方便，所以我用自定义函数XEscapeRegex()对选择的内容做这个事，不过最完美的方法当然是Ferret自己支持，或者自己再封装一下Ferret的命令，这样输入的正则表达式可读性就正常了。&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;Ferret 的另一个优点是可以对搜索结果做筛选，删除不需要做替换的行，再对剩下的行执行批量替换。当执行替换命令 &lt;code&gt;:Acks&lt;/code&gt; 时，会自动把上一个 &lt;code&gt;:Ack&lt;/code&gt; 命令中的正则表达式或关键词补全到命令的参数中。&lt;/p&gt;
&lt;p&gt;Ferret 最大的问题在于，搜索使用 rg 、 ag 这样的命令行工具，而替换使用 Vim 内置的 &lt;code&gt;:substitute&lt;/code&gt; 命令。前者使用 PCRE 正则表达式，而后者使用 Vim 自己的正则表达式。两者在格式上的不兼容导致对一些复杂的 pattern 做搜索和替换时，往往需要对 pattern 做修改才能正常对之前的搜索结果做替换。关于这个问题，后面细说。&lt;/p&gt;</description></item><item><title>Bose QC35，这安静有毒</title><link>http://0x3f.org/posts/the-experience-of-bose-qc35/</link><pubDate>Sat, 18 Feb 2017 20:23:28 +0000</pubDate><guid>http://0x3f.org/posts/the-experience-of-bose-qc35/</guid><description>&lt;p&gt;&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvwyum8eyj31kw11y1kx.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我很容易受环境影响，即便在家里比较安静的时候，也经常集中不了注意力。小时候总是可以连续几个小时读一本书，现在已经很久没有长时间专心做一件事了。戴了一段时间QC35，又重新找回了这种感觉，干什么事都很专心，感觉很安静，心态平和很多。&lt;/p&gt;
&lt;p&gt;之前先入手了森海大馒头，不过没有降噪的功能，所以必须一直配合白噪声使用，时间长了还是有点累的。另外，有线耳机实在不方便，所有的数码设备都应该无线化，对生活品质的提升会很大。虽然大馒头作为出街向的东西，手机也推得动，但是要发挥音质，还是得上耳放，我不是发烧友，这木耳就算了。&lt;/p&gt;
&lt;p&gt;所以对QC35长草很久了，后来大法又出了MDR 1000X，作为对标QC35的东西，有这些优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;独立的降噪开关&lt;/li&gt;
&lt;li&gt;手势操作&lt;/li&gt;
&lt;li&gt;快速反应模式&lt;/li&gt;
&lt;li&gt;音质&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;QC35的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;穿戴更舒适&lt;/li&gt;
&lt;li&gt;同时连接两个设备&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于耳机，我的核心需求是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;降噪效果好&lt;/li&gt;
&lt;li&gt;无线&lt;/li&gt;
&lt;li&gt;舒适&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在满足核心需求的基础上，选择有价格优势的东西。1000X肯定更方便，不过没有这些功能好像问题也不大。而且有些噱头的实际体验究竟有多好，我是有疑问的，比如手势的误操作问题。在我看来，为这些噱头买单不值，所以最后选了QC35。&lt;/p&gt;
&lt;p&gt;使用一段时间下来体验确实很好，已经对这久违的安静上瘾了，长时间戴也没有不适感，同时连接电脑和手机也很方便。&lt;/p&gt;</description></item><item><title>Postman: Could Not Get Any Response</title><link>http://0x3f.org/posts/postman-could-not-get-any-response/</link><pubDate>Tue, 14 Feb 2017 14:37:54 +0000</pubDate><guid>http://0x3f.org/posts/postman-could-not-get-any-response/</guid><description>&lt;p&gt;Postman如果不显示API返回结果，而是报错：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Could not get any response&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;有一种原因是响应的header存在错误：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx7lf9t7j30jd04fq3q.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;图中以双引号开头的第一行是有问题的。&lt;/p&gt;
&lt;p&gt;PS：&lt;a href="https://httpie.org"&gt;httpie&lt;/a&gt;是个好东西。&lt;/p&gt;</description></item><item><title>用NGINX实现WSS</title><link>http://0x3f.org/posts/implement-wss-with-nginx/</link><pubDate>Tue, 14 Feb 2017 13:35:41 +0000</pubDate><guid>http://0x3f.org/posts/implement-wss-with-nginx/</guid><description>&lt;p&gt;实现基于SSL的安全的WebSocket。&lt;/p&gt;
&lt;h2 id="nginx配置"&gt;NGINX配置&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;server {
listen 4431;
server_name ws.sample.com;
ssl on;
ssl_certificate ssl/server.crt;
ssl_certificate_key ssl/server.key;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
ssl_protocols SSLv3 SSLv2 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
location /
{
proxy_pass http://127.0.0.1:4759;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection &amp;#34;Upgrade&amp;#34;;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 60s;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="常见问题"&gt;常见问题&lt;/h2&gt;
&lt;h3 id="连不上或连接时报错"&gt;连不上或连接时报错&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;WebSocket network error: OSStatus Error -9807: Invalid certificate chain&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果使用的是自签证书或者证书针对的域名和连接所指定的不符，会出这种问题。&lt;/p&gt;
&lt;h3 id="wss一分钟自动断开"&gt;wss一分钟自动断开&lt;/h3&gt;
&lt;p&gt;NGINX里设置proxy_read_timeout或者程序实现心跳。&lt;/p&gt;</description></item><item><title>WebSocket: Connection Header Value Must Contain Upgrade</title><link>http://0x3f.org/posts/websocket-connection-header-value-must-contain-upgrade/</link><pubDate>Sat, 11 Feb 2017 21:52:30 +0000</pubDate><guid>http://0x3f.org/posts/websocket-connection-header-value-must-contain-upgrade/</guid><description>&lt;p&gt;用NGINX反向代理实现WSS后，创建连接时报错：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Error during WebSocket handshake: &amp;lsquo;Connection&amp;rsquo; header value must contain &amp;lsquo;Upgrade&amp;rsquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据&lt;a href="http://nginx.org/en/docs/http/websocket.html"&gt;官方文档&lt;/a&gt;，NGINX从1.3.13开始才支持这个特性，所以解决方法是升级到最新版。&lt;/p&gt;</description></item><item><title>Git Reset、Revert和Checkout的区别</title><link>http://0x3f.org/posts/differences-among-reset-checkout-revert-of-git/</link><pubDate>Thu, 09 Feb 2017 19:27:47 +0000</pubDate><guid>http://0x3f.org/posts/differences-among-reset-checkout-revert-of-git/</guid><description>&lt;p&gt;reset在提交层面，是将HEAD设定到指定的提交，通常用来舍弃最新的几个提交。在文件层面，是将指定的提交中的该文件保存到暂存区，工作区中的文件不变。&lt;/p&gt;
&lt;p&gt;reset有三个常用的参数：--mixed、--soft和--hard。&lt;/p&gt;
&lt;p&gt;在提交层面，--mixed是默认值，影响暂存区，不影响工作区；--soft将HEAD版本保存到暂存区，并将HEAD设定到指定的提交，用来合并提交历史；--hard既影响暂存区，也影响工作区。&lt;/p&gt;
&lt;p&gt;在文件层面，--soft和--hard均会报错，不支持这两个选项。&lt;/p&gt;
&lt;p&gt;在提交层面，执行过reset后如果需要撤销，使用reflog命令查看之前HEAD的hash，通过reset --hard恢复到该版本。&lt;/p&gt;
&lt;p&gt;checkout在提交层面，用来切换分支或检出到指定的提交。对于后者，如果增加了新的提交，在切换到其它分支后，再切换回来时，这些提交将会丢失，如果希望保存这些提交，在切换到其它分支前，创建一个新的分支。&lt;/p&gt;
&lt;p&gt;revert用来通过创建一个新的提交来回滚一个提交，因此，和reset不同，并不会改变提交的历史。&lt;/p&gt;
&lt;p&gt;对于回滚一次提交的场景，revert比reset安全，所以revert适用于公共分支，reset适用于私有分支。&lt;/p&gt;</description></item><item><title>从 Octopress 迁移到 Hexo</title><link>http://0x3f.org/posts/migrate-octopress-to-hexo/</link><pubDate>Wed, 08 Feb 2017 20:24:16 +0000</pubDate><guid>http://0x3f.org/posts/migrate-octopress-to-hexo/</guid><description>&lt;p&gt;因为原来的主题没有针对中文优化，显示效果不太好，在搜索新主题的时候顺便了解了一下其它几个静态博客生成工具，发现Hexo比Octopress有很大的优势，就迁移了过来。&lt;/p&gt;
&lt;p&gt;Hexo的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;速度快：几百篇文章只需要几秒，而Octopress需要几十秒&lt;/li&gt;
&lt;li&gt;易用：配置、部署简单，文章被修改后会立即更新浏览器中的预览页面&lt;/li&gt;
&lt;li&gt;轻量：基于node.js，目录结构简明&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;迁移的过程不算顺利，先是遇到「MODULE_NOT_FOUND」的问题，搜到的方法都不起作用，原因大概是因为墙的问题导致dtrace模块安装出错，理论上用代理安装是可以解决的，结果在反复安装的过程中莫名其妙地就好了。&lt;/p&gt;
&lt;p&gt;再一个问题是选主题，喜欢极简的风格，但是极简又大气的主题很少，相对最喜欢的是&lt;a href="https://github.com/yuche/hexo-theme-kael"&gt;kael&lt;/a&gt;，不过生成速度非常慢，而且生成的页面有大量乱码。于是退而求其次，选择了&lt;a href="https://github.com/guolin/crisp-hexo-theme"&gt;crisp&lt;/a&gt;。然而还是有不满意的地方，比如过于简单、没有搜索、不区分首页和归档等，还有待自己修改。&lt;/p&gt;</description></item><item><title>Calibre排版的最佳实践</title><link>http://0x3f.org/posts/best-practices-of-calibre-on-formatting/</link><pubDate>Fri, 27 Jan 2017 18:15:00 +0000</pubDate><guid>http://0x3f.org/posts/best-practices-of-calibre-on-formatting/</guid><description>&lt;p&gt;&lt;strong&gt;虽然如今左Kindle、右iPad，但是再也没有在课堂上用文曲星看《此间的少年》的感觉。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;忘了前段时间看池建强还是和菜头的文章，说很讨厌中文排版中段落首行缩进的风格，深有同感。我一般在读前会先用Calibre修改一下书的格式，段落首行不缩进、用空白行分割段落、嵌入好看的字体，否则强迫症表示根本看不下去。&lt;/p&gt;
&lt;p&gt;本文分享几则平时积累的Calibre排版的最佳实践，顺带吐槽一下亚马逊电子书的排版质量，早已经被微信读书、多看这些APP吊打了。&lt;/p&gt;
&lt;h2 id="一最佳排版"&gt;一、最佳排版&lt;/h2&gt;
&lt;p&gt;最小行高：140%。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvx83ybpbj30az0a5t9f.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;使用空白行分段，段落首行不缩进。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx2.sinaimg.cn/large/006tNbRwly1fwvx8hwq08j30gc03lmxh.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;要嵌入字体，必须转换成KF8格式的类型，例如azw3或者both类型的mobi：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvx8znehdj30av06dmxo.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;注意：KF8格式在点选文字时，默认选中一句，而不是单字，不方便查字典。要默认选中单字，须转换成old类型的mobi。&lt;/p&gt;
&lt;h2 id="二最佳字体"&gt;二、最佳字体&lt;/h2&gt;
&lt;p&gt;索尼楷书&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx4.sinaimg.cn/large/006tNbRwly1fwvx92ktu8j30ts148jys.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;方正北魏楷书&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvx9fm9nlj30ts148dn4.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;方正宋三&lt;/p&gt;
&lt;p&gt;在微信读书iOS上显示效果很好，但是在Kindle里比较一般。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>两条分组的SQL语句</title><link>http://0x3f.org/posts/two-grouping-sql-statements/</link><pubDate>Fri, 27 Jan 2017 17:51:00 +0000</pubDate><guid>http://0x3f.org/posts/two-grouping-sql-statements/</guid><description>&lt;p&gt;最近做访问统计解决的两个问题：&lt;/p&gt;
&lt;h2 id="根据日期分组"&gt;根据日期分组&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1485014400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;from_unixtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Y-%m-%d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1484928000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1485014400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;from_unixtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Y-%m-%d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;distinct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="k"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1484496000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;group&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1485014400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;from_unixtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Y-%m-%d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1484928000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1485014400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;from_unixtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Y-%m-%d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="选择每组数据的第一条"&gt;选择每组数据的第一条&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;province&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;referer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;statistics&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;inner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;join&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;statistics&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;group&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latest_time&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;desc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>用OpenResty自动转换silk到MP3</title><link>http://0x3f.org/posts/convert-silk-to-mp3-with-openresty/</link><pubDate>Wed, 25 Jan 2017 18:59:00 +0000</pubDate><guid>http://0x3f.org/posts/convert-silk-to-mp3-with-openresty/</guid><description>&lt;p&gt;PHP没有原生的转换silk格式音频到mp3的方案，所以考虑用NGINX+Lua调用命令行工具实现。&lt;/p&gt;
&lt;h2 id="思路"&gt;思路&lt;/h2&gt;
&lt;p&gt;当访问以「.silk.mp3」为后缀的文件时，查找对应的mp3文件，存在则返回，否则，如果对应的silk文件存在，调用命令行工具转换文件格式，然后内部重定向到新生成的mp3。&lt;/p&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openresty.org/cn/download.html"&gt;OpenResty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kn007/silk-v3-decoder"&gt;silk-v3-decoder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ffmpeg.org"&gt;ffmpeg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="nginx配置"&gt;NGINX配置&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;/.*\.silk\.mp3&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;content_by_lua_file&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;/opt/script/silk2mp3.lua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="lua脚本"&gt;Lua脚本&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;io.open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;~=&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;io.close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ngx.var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_filename&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;realResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;.mp3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;realURI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ngx.var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;ngx.var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;.mp3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;realResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ngx.exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;realURI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;silk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;silk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ngx.exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;os.execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/bin/sh /opt/silk-v3-decoder/converter.sh &lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;silk&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;&lt;/span&gt;&lt;span class="s2"&gt; mp3 &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;realResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ngx.exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;realURI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ngx.exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="遇到的问题"&gt;遇到的问题&lt;/h2&gt;
&lt;h3 id="openresty调用命令转换失败而手工可以"&gt;OpenResty调用命令转换失败，而手工可以&lt;/h3&gt;
&lt;p&gt;silk-v3-decoder的converter.sh把所有错误信息都屏蔽了，需要修改脚本查看。&lt;/p&gt;</description></item><item><title>微软识花和形色</title><link>http://0x3f.org/posts/two-plant-identification-apps/</link><pubDate>Wed, 28 Dec 2016 12:12:00 +0000</pubDate><guid>http://0x3f.org/posts/two-plant-identification-apps/</guid><description>&lt;p&gt;由于微软的名气，「微软识花」刚推出的时候就众所周知。很好用的App，我成功地用它识别出了母上的长春花：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx3.sinaimg.cn/large/006tNbRwly1fwvwwr9lsgj30zk0qodhw.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;不过我养的主要是观叶植物，只能识别花对我来说意义不大。直到最近发现了「形色」。识别率还不错，对特征不明显的植物容易误报，比如我的空凤就被识别成了吊兰……&lt;/p&gt;
&lt;p&gt;&lt;img src="https://wx1.sinaimg.cn/large/006tNbRwly1fwvwwu1rsdj31kw1kw1kx.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这就是「微软识花」狡猾的地方。&lt;/p&gt;</description></item><item><title>小确幸，用Vim编辑当前命令行</title><link>http://0x3f.org/posts/edit-command-with-vim/</link><pubDate>Mon, 26 Dec 2016 11:58:00 +0000</pubDate><guid>http://0x3f.org/posts/edit-command-with-vim/</guid><description>&lt;p&gt;修改很长的命令是件痛苦的事，在Linux下，可以通过快捷键&lt;code&gt;Ctrl+X Ctrl+E&lt;/code&gt;调用&lt;code&gt;$EDITOR&lt;/code&gt;快速编辑当前命令行的内容，保存退出后，结果会呈现在光标下。&lt;/p&gt;
&lt;p&gt;不过在Mac OS的iTerm2下，似乎是因为&lt;code&gt;Ctrl+X&lt;/code&gt;被占用而不能生效。误打误撞地发现了另外一个方法，使用oh-my-zsh并且开启了vi mode的话，先进入vi mode，然后输入&lt;code&gt;v&lt;/code&gt;，同样可以实现这样的功能。&lt;/p&gt;</description></item><item><title>用锐速加速Shadowsocks</title><link>http://0x3f.org/posts/accelerate-shadowsocks-with-serverspeeder/</link><pubDate>Sun, 25 Dec 2016 15:39:00 +0000</pubDate><guid>http://0x3f.org/posts/accelerate-shadowsocks-with-serverspeeder/</guid><description>&lt;p&gt;各种VPS加速方案一般都是重复发包的原理，也就是用流量换速度。&lt;/p&gt;
&lt;p&gt;先尝试了kcptun，因为据说资源占用很低，不过部署后打不开网页。然后试了一下锐速，用一键脚本安装，很方便，而且不像kcptun，不需要客户端。部署前在Youtube只能看最低清晰度，现在在网络条件好的情况下，720p也不卡，效果很明显。&lt;/p&gt;
&lt;p&gt;不过锐速不支持OpenVZ，所以搬瓦工用不了，我用的 &lt;a href=""&gt;Vultr&lt;/a&gt; 东京机房的基础配置。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.91yun.org/archives/683"&gt;锐速破解版linux一键自动安装包&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Vultr基配可以部署Gitlab</title><link>http://0x3f.org/posts/setup-gitlab-on-vultr-basic-vps/</link><pubDate>Sat, 24 Dec 2016 17:18:00 +0000</pubDate><guid>http://0x3f.org/posts/setup-gitlab-on-vultr-basic-vps/</guid><description>&lt;p&gt;想在Vultr上部署Gitlab，但是官方文档上说最低要求1GB RAM + 3GB swap，而我的VPS是基础配置：768MB RAM。&lt;/p&gt;
&lt;p&gt;忐忑地试了一下，居然可以用，只是重启防火墙的时候CPU一直100%，最后reboot了事。&lt;/p&gt;
&lt;h2 id="环境"&gt;环境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CentOS 7 x64&lt;/li&gt;
&lt;li&gt;Gitlab CE 8.15&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.vultr.com/docs/setup-swap-file-on-linux"&gt;Setup Swap File on Linux - Vultr.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://about.gitlab.com/downloads/#centos7"&gt;Installation Guide of GitLab Community Edition | GitLab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>关于李陵的更多细节</title><link>http://0x3f.org/posts/more-about-li-ling/</link><pubDate>Thu, 22 Dec 2016 19:41:00 +0000</pubDate><guid>http://0x3f.org/posts/more-about-li-ling/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619161610000-dda16288015d2abe5c39702b4fa1d2ef.avif" alt="2020-06-19-16-16-10-20161021001"&gt;&lt;/p&gt;
&lt;p&gt;上次聊了李陵败降的细节。在此之后，还发生了几件有意思的事。&lt;/p&gt;
&lt;p&gt;第一个细节，是武帝并没有马上杀掉李陵全家，甚至在第二年，还派一支军队营救他。&lt;/p&gt;
&lt;p&gt;毕竟累世将门，李陵的军事才能武帝是很欣赏的，况且对于李广的死，武帝不能没有一点愧疚。五千步兵深入匈奴，仗打成这个样子已经是虽败尤胜了，这一点，武帝自己是知道的，之所以迁怒司马迁，主要是因为李陵没有死，而是降了。&lt;/p&gt;
&lt;p&gt;在这次战役中，武帝本来给李陵安排的任务是给李广利作后勤保障，是李陵自己不干，非要率五千步兵涉单于庭。按武帝的想法，李陵真要打赢也行，毕竟事关生死存亡，再不济也得战死沙场。领导给安排的活你不干，你自己吹那么大的牛又没做到，最后还投降了，这是武帝生气的主要原因。&lt;/p&gt;
&lt;p&gt;不过武帝还是惜才的，所以第二年就派了一支军队去救李陵。不过这支军队转了一圈没捞著匈奴人的影子，只带回来一个传闻——李陵在教匈奴人对付汉军的方法。武帝随即大怒，并处决了李陵一家。&lt;/p&gt;
&lt;p&gt;后来，汉朝有人出使匈奴，李陵趁机问汉使：「我自问战功不负朝廷，为什么杀我全家？」汉使就说出了这个传闻。李陵大恨，说这事是一个叫李绪的干的。李绪也是一个汉朝的降将，因为这件事，李陵痛恨李绪，就派人把他刺杀了。可能李绪是大阏氏的人，所以大阏氏就要杀李陵。因为匈奴有浓重的母系氏族的风俗残留，所以大阏氏的势力很大，连单于也要让三分。于是单于只能把李陵藏到很远的地方，直到后来大阏氏死了，才敢接回来。&lt;/p&gt;
&lt;p&gt;第二个细节，是霍光曾经试图策反李陵。&lt;/p&gt;
&lt;p&gt;李陵在汉朝的时候跟霍光私交不错，所以武帝死后，霍光辅政，就想著把李陵接回来，于是以出使的名义派人到匈奴和李陵接头。李陵沈吟良久，说了一句话：「大丈夫不能再次受辱。」最终拒绝了。&lt;/p&gt;
&lt;p&gt;李陵的决定是正确的，作为一个有污点的人，回到汉朝纵然有权臣罩著，一旦靠山倒了，覆巢之下也无完卵。何况至亲已死，在汉朝已无牵挂，哪比得上在那天高原阔的地方做一个部落王。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>哪个时代都看脸</title><link>http://0x3f.org/posts/judge-by-face/</link><pubDate>Fri, 09 Dec 2016 21:39:00 +0000</pubDate><guid>http://0x3f.org/posts/judge-by-face/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619161610000-dda16288015d2abe5c39702b4fa1d2ef.avif" alt="2020-06-19-16-16-10-20161021001"&gt;&lt;/p&gt;
&lt;p&gt;汉书卷四十二：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;苍当斩，解衣伏质，身长大，肥白如瓠，时王陵见而怪其美士，乃言沛公，赦勿斩。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;高晓松特喜欢说一句话——这是个看脸的时代。其实哪个时代都看脸，所以张苍因为高胖白，捡了一条命。&lt;/p&gt;
&lt;p&gt;昨天读汉书司马相如传，讲到撩妹那段（&lt;em&gt;以琴心挑之&lt;/em&gt;），后面紧接著就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;相如时从车骑，雍容闲雅，甚都。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;翻译成人话就是：相如经常开著跑车，逼格满满，很帅。所以你以为光琴弹得好就行了么，想想贝多芬的《献给爱丽丝》。&lt;/p&gt;
&lt;p&gt;看脸本无可厚非，有意思的是看脸的规律：因时而异，因境而异。&lt;/p&gt;
&lt;p&gt;先说后者。家世好的喜瘦，苦出身的喜肥。所以楚王好细腰，宫人多饿死。所以赵飞燕能作掌中舞，于是汉成帝死在赵合德的床上。所以屌丝出身的刘邦和王陵饶了张胖子一命。&lt;/p&gt;
&lt;p&gt;因时而异。乱世尚刚，治世尚柔。季世丧乱，生存是第一命题，社会的整体审美一定是趋于阳刚的，最好脸上再有道疤，活活美死。而由乱入治，公共审美一定趋于女性化。最典型的就是魏晋南北朝，这时期的男人，要剃须、薰香、涂胭脂，甚至头上还插花。&lt;/p&gt;
&lt;p&gt;有个南北互飚花美男的故事。大致的情节是这样的：南方派了一个花美男出使北方，结果都城万人空巷，北方朝廷一看，心说不能让人给比下去啊，就也挑了一个小鲜肉出使南方，于是南方都城里也万头攒动。&lt;/p&gt;
&lt;p&gt;这个故事我不记得出处了，不过《世说新语》的《容止》篇里随便挑一条，都不忍直视：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;王丞相见卫洗马曰：「居然有羸形，虽复终日调畅，若不堪罗绮。」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不堪罗绮，羡杀韩国欧巴和国产小鲜肉们。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>李陵是作死的</title><link>http://0x3f.org/posts/no-zuo-no-die/</link><pubDate>Thu, 01 Dec 2016 20:47:00 +0000</pubDate><guid>http://0x3f.org/posts/no-zuo-no-die/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619161610000-dda16288015d2abe5c39702b4fa1d2ef.avif" alt="2020-06-19-16-16-10-20161021001"&gt;&lt;/p&gt;
&lt;p&gt;汉书卷五十四：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;陵对：「无所事骑，臣愿以少击众，步兵五千人涉单于庭。」上壮而许之……&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于李陵的遭遇，多数人从司马迁身上多少都是知道的：祖上是追杀燕太子丹的秦将李信，祖父是飞将军李广，出身将门世家的李陵自然骁武凭陵，以五千步兵力战十万匈奴精骑，最后矢尽援绝，不得已才投降。即便对于信仰「文死谏，武死战」的中国人，多数也是同情的。&lt;/p&gt;
&lt;p&gt;然而这个故事主要来自于史记，这就尴尬了。从某种意义上说，李陵是给史记定下基调的人。这就决定了它展示给读者的不会是故事的全貌。比如很多年前，我第一次看到这个故事的时候就想不明白一个问题：用五千步兵孤军远征游牧的匈奴，傻子都知道胜算很小，刘彻和李陵的智商同时下线了？&lt;/p&gt;
&lt;p&gt;最近读到汉书的李陵传，发现了更多有趣的细节。&lt;/p&gt;
&lt;p&gt;天汉二年，武帝命二师将军李广利出兵三万攻打在天山的匈奴右贤王，想让李陵监押辎重。**如果把武帝的军事史浓缩成一句话，那就是刘彻和他的小舅子们。**李广利就是因为裙带关系上位的，所以将门世家的李陵耻于为其搞后勤，就跟武帝说：「我本部的军队都是精锐，希望能单独出兵一路，这样可以迫使匈奴人分兵，二师将军那边的压力也会轻一些。」武帝多精啊，一眼就识破李陵的小九九，说：「这次我出兵很多，没有富余的骑兵给你。」&lt;/p&gt;
&lt;p&gt;于是李陵就开始作了，就有了本文开头的那句话。以少击众、步兵打骑兵、孤军深入，哪一条都是兵家大忌，估计李陵说这句话时头皮都是硬的。&lt;/p&gt;
&lt;p&gt;当然李陵也不是完全没有资本，**汉军的战斗力是超过匈奴人的。**硬碰硬的正规战争，匈奴人败多胜少。因为战争打的是综合实力，无论是经济实力、人口、技术，汉朝都远超匈奴，即使三岁骑马五岁弯弓的匈奴人的单兵素质超过汉朝的民兵。&lt;/p&gt;
&lt;p&gt;后来的战事就证明了这一点。首战浚稽山，匈奴人就损失数千人，汉军步兵还追著骑兵打。主要原因就是经济和技术水平的落差太大。匈奴人主要装备的是弓箭，箭头是用兽骨和石头磨成的片状，汉军装备的是连弩，箭头是金属质三棱状，无论在射速、穿透力还是精准度上，前者都远远落后于后者。所以转战上千里，坚持很多天，直到最后汉军的箭用完了，匈奴人才在距离边境五十公里的地方吃掉这支孤军。换句话说，如果箭量充足，十万匈奴骑兵都打不过五千汉军步兵，这个战力的对比，很明显吧。&lt;/p&gt;
&lt;p&gt;最后不服从领导安排的李陵还是败了，败在距离边境只有五十公里的地方。据说最后的日子里，他还单独出营一次，理由是想刺杀单于，搞个斩首行动，回来后就彻底丧失了战斗意志。我觉得这又是个疑点，是不是想溜啊。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>改用Bear记笔记</title><link>http://0x3f.org/posts/switch-to-bear/</link><pubDate>Mon, 14 Nov 2016 23:32:00 +0000</pubDate><guid>http://0x3f.org/posts/switch-to-bear/</guid><description>&lt;p&gt;再次证明我是后知后觉的。&lt;/p&gt;
&lt;p&gt;曾经对印象笔记不屑一顾，因为对所见即所得的偏见和印象笔记对技术人员的不友好。所以这些年一直用DokuWiki。&lt;/p&gt;
&lt;p&gt;DW的编辑模式不是传统的所见即所得，自己的wiki标记简洁好用。能针对段落进行修改。可以列出大纲。插件和主题较多。使用文件存储数据，方便同步。平台无关，对Linux友好。&lt;/p&gt;
&lt;p&gt;不过DW自身也存在一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要搭建服务&lt;/li&gt;
&lt;li&gt;自行处理同步&lt;/li&gt;
&lt;li&gt;移动端访问不便&lt;/li&gt;
&lt;li&gt;编辑和查看操作有割裂感&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最近开始琢磨记笔记的最佳实践。考虑到用DW的痛点，感觉对于记笔记最重要的是是否方便记录和查看。在这点上，所见即所得的确有优势。所以我尝试转换到这类工具上。&lt;/p&gt;
&lt;p&gt;选择Bear而不是印象笔记的原因主要是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持代码语法高亮&lt;/li&gt;
&lt;li&gt;支持导出Markdown格式&lt;/li&gt;
&lt;li&gt;极简风和多种主题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码语法高亮是刚需，没什么可说的。导出Markdown格式可以方便写博客，这样就不需要Cmd Markdown了。极简的风格和包括Solarized在内的多种主题很毒我。&lt;/p&gt;
&lt;p&gt;不过Bear也有不少问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有大纲视图，不适合长笔记&lt;/li&gt;
&lt;li&gt;标签只支持两级，大量标签不好管理&lt;/li&gt;
&lt;li&gt;不支持扫描&lt;/li&gt;
&lt;li&gt;对Linux不友好&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用标签替代分类的方式我很喜欢，不过两级的限制让笔记分类很伤脑筋，而且容易造成标签太多、难以管理。扫描也是刚需，印象笔记的扫描就很好用，Bear目前没有这个功能，只能用扫描全能王暂补，割裂感很强，而且还增加了APP。&lt;/p&gt;
&lt;p&gt;希望Bear尽快变得更好用。&lt;/p&gt;</description></item><item><title>JSON是对象还是字符串？</title><link>http://0x3f.org/posts/what-is-json/</link><pubDate>Tue, 08 Nov 2016 10:46:00 +0000</pubDate><guid>http://0x3f.org/posts/what-is-json/</guid><description>&lt;p&gt;前两天，一个前端跟我争论说JSON是对象。我在接口文档里的数据格式写的是JSON，结果对方真就传了个对象过来。&lt;/p&gt;
&lt;p&gt;要搞清楚JSON是什么，先得知道JSON是为了解决什么问题的。维基百科里的定义是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JSON（JavaScript Object Notation）是一种由道格拉斯·克罗克福特构想设计、轻量级的数据交换语言，以文字为基础，且易于让人阅读。尽管JSON是Javascript的一个子集，但JSON是独立于语言的文本格式，并且采用了类似于C语言家族的一些习惯。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以说，JSON是为了解决语言之间数据交换的一种文本格式，体现在数据上，JSON就是字符串类型。那么为什么需要为数据交换制订一种通用的文本格式呢？可以做一个简单的试验：&lt;/p&gt;
&lt;p&gt;用JavaScript建立一个到PHP的WebSocket并发送一个对象：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ws://127.0.0.1:4759&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;PHP接收并打印对象：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Workerman\Worker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;websocket://0.0.0.0:4759&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$worker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;onMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;runAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;得到的结果是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[object Object]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以，一种语言的对象的实例以二进制形式直接传递给另一种语言是无法识别的，因此需要把对象数据用文本描述之后再行传递。&lt;/p&gt;
&lt;p&gt;此外，相对于XML等其它格式，JSON有可读性上的优势，如果是对象，二进制的数据哪来的可读性？&lt;/p&gt;</description></item><item><title>在Vim窗口标题中显示会话名</title><link>http://0x3f.org/posts/show-session-name-in-vim-window-title/</link><pubDate>Sun, 23 Oct 2016 11:52:00 +0000</pubDate><guid>http://0x3f.org/posts/show-session-name-in-vim-window-title/</guid><description>&lt;p&gt;同时处理多个项目时，在窗口标题中显示会话名，方便区分，需用&lt;a href="https://github.com/xolox/vim-session"&gt;session&lt;/a&gt;管理会话。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; custom the window title&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;MyTitleString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sessionName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;xolox&lt;/span&gt;#&lt;span class="nx"&gt;session&lt;/span&gt;#&lt;span class="nx"&gt;find_current_session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sessionStr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionName&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sessionStr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; [&amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;sessionName&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;] &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;VIM&amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;sessionStr&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;: %-25.55F %a%r%m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;endfun&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;BufEnter&lt;/span&gt; * &lt;span class="k"&gt;let&lt;/span&gt; &amp;amp;&lt;span class="nx"&gt;titlestring&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;MyTitleString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;titlelen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;70&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>时人食狗亦与羊豕同</title><link>http://0x3f.org/posts/thinkings-about-eating-dogs/</link><pubDate>Fri, 21 Oct 2016 13:21:00 +0000</pubDate><guid>http://0x3f.org/posts/thinkings-about-eating-dogs/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619161610000-dda16288015d2abe5c39702b4fa1d2ef.avif" alt="2020-06-19-16-16-10-20161021001"&gt;&lt;/p&gt;
&lt;p&gt;汉书卷四十一：「樊哙，沛人也，以屠狗为事。」&lt;/p&gt;
&lt;p&gt;颜师古注：「时人食狗亦与羊豕同。」&lt;/p&gt;
&lt;p&gt;狗对于中国古人的意义和西方人不同。西方人，确切的说是美国人，对狗的感情完全是因为发展的时间太晚。美国开国也就二百来年，从印地安人手里夺来的大量耕地和牧场保证了充足的食物来源，而狗为地广人稀的美国在开拓过程中提供了重要的陪伴和保护，所以美国人不吃狗。&lt;/p&gt;
&lt;p&gt;中国发展的时间远早于美国，而且没有大片的牧场提供稳定的肉食来源，大型牲畜作为农业主要替代劳力一般也不会用于食用，甚至历朝长期立法禁止宰杀大型牲畜。所以狗长期是作为一种重要的肉食来源。&lt;/p&gt;
&lt;p&gt;「失我祈连山，使我六畜不藩息」，「六畜」分别是猪、牛、羊、马、鸡、狗，这是最早被中国人驯化并作为肉食来源的牲畜，而且长期作为祭祀天地祖宗的高档祭品。《道德经》里说：「天地不仁，以万物为刍狗」。「刍狗」就是草扎的狗，是祭祀时当祭品用的，祭祀的时候高高在上、被人们顶礼膜拜，祭祀之后被弃之如敝履，所以说天地不仁。之所以用草狗做祭品，是生产力进步的表现，最初一定是用真狗的，只是后来更高档的肉食逐渐普及，狗肉上不了台面了，才逐渐被抽象成草偶。&lt;/p&gt;
&lt;p&gt;所以中国人是有吃狗的传统的，美国人不吃狗肉也并不表示更文明，至于「狗是人类的朋友」，更是道德绑架，谁也不能随便替别人认朋友，最多只能说你的狗是你的朋友，如果别人吃的不是你的朋友，即便自以为站在道德的高度，你也没有任何权力干涉别人的自由，有句话说的好：自由，就是我有不和你一样高尚的权利。&lt;/p&gt;
&lt;p&gt;我个人也不吃狗肉，但我不觉得别人吃来源合法的狗肉有什么问题。事实上，吃狗肉的问题并不在于吃不吃本身，而是在这个问题上表现出来的人性的恶，人总是自以为站在道德的高度就可以践踏别人的权利，每个暴政无不是利用人性的这个弱点。&lt;/p&gt;
&lt;p&gt;切记，儒以文乱法。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Archlinux安装过程中的几个坑</title><link>http://0x3f.org/posts/pits-of-archlinux/</link><pubDate>Mon, 17 Oct 2016 13:14:00 +0000</pubDate><guid>http://0x3f.org/posts/pits-of-archlinux/</guid><description>&lt;h2 id="安装方案"&gt;安装方案&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://mirrors.ustc.edu.cn/archlinux/iso/archboot/latest/"&gt;Archboot&lt;/a&gt;是比官方镜像更友好的安装媒介，此外还有&lt;a href="https://github.com/helmuthdu/aui"&gt;AUI&lt;/a&gt;和&lt;a href="https://arch-anywhere.org"&gt;Arch Anywhere&lt;/a&gt;，没有试过。&lt;/p&gt;
&lt;h2 id="分区"&gt;分区&lt;/h2&gt;
&lt;p&gt;Archboot使用parted处理分区任务。&lt;/p&gt;
&lt;p&gt;第一个分区不能从sector 0开始，否则安装完成后系统玩法启动，报如下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;no operating system found&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;正确的姿势：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;(parted) mkpart primary 2048s 512&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以上假设第一个分区用来挂载/boot，分配512M。&lt;/p&gt;
&lt;p&gt;还需要设置/boot所在的分区可启动：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;(parted) set 1 boot on&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="启动引导器"&gt;启动引导器&lt;/h2&gt;
&lt;p&gt;GRUB的兼容性比较好。&lt;/p&gt;
&lt;p&gt;如果是syslinux，对于没有单独对/boot分区并且根分区使用ext4的情况，会无法启动，报如下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;failed to load ldlinux.c32&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;此时，应对/boot单独分区并使用fat格式。&lt;/p&gt;
&lt;h2 id="图形界面"&gt;图形界面&lt;/h2&gt;
&lt;p&gt;安装X不会连带安装显卡驱动，要单独安装，否则启动图形界面会黑屏。&lt;/p&gt;
&lt;p&gt;在VirtualBox中安装时，驱动在「virtualbox-guest-utils」。&lt;/p&gt;</description></item><item><title>小确幸，用shift切换输入法</title><link>http://0x3f.org/posts/little-happiness-from-replacing-ctrl-space-with-shift/</link><pubDate>Sat, 17 Sep 2016 15:36:00 +0000</pubDate><guid>http://0x3f.org/posts/little-happiness-from-replacing-ctrl-space-with-shift/</guid><description>&lt;p&gt;把Alfred升级到3，就想著把切换中英输入状态的问题一块解决掉。&lt;/p&gt;
&lt;p&gt;Alfred可以设置默认使用英文输入状态，然后用Karabiner把Shift_L映射成Ctrl+Space。现在切换输入状态和用Alfred的效率都高多了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Shift_L to Shift_L&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;appendix&amp;gt;&lt;/span&gt; + When you type Shift_L only,change to previous system input method&lt;span class="nt"&gt;&amp;lt;/appendix&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;appendix&amp;gt;&lt;/span&gt;Shift_L == (Ctrl-Space)&lt;span class="nt"&gt;&amp;lt;/appendix&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;identifier&amp;gt;&lt;/span&gt;private.change_input_source_to_squirrel.Rime&lt;span class="nt"&gt;&amp;lt;/identifier&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;autogen&amp;gt;&lt;/span&gt;__KeyOverlaidModifier__ KeyCode::SHIFT_L, ModifierFlag::SHIFT_L | ModifierFlag::NONE, KeyCode::SHIFT_L, KeyCode::SPACE,ModifierFlag::CONTROL_L&lt;span class="nt"&gt;&amp;lt;/autogen&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>读完《走出帝制》</title><link>http://0x3f.org/posts/after-reading-walking-out-of-the-imperial/</link><pubDate>Thu, 30 Jun 2016 16:19:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-walking-out-of-the-imperial/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619161858000-80bea4acae9ab252adb19c8c9fbcfe29.avif" alt="2020-06-19-16-18-58-20160630001"&gt;&lt;/p&gt;
&lt;p&gt;用了四天时间，读完了这本书。之所以叫「这本书」，是因为这是本在豆瓣里都找不到记录的书，去年上市不久即被下架，通常意义上，叫禁书。&lt;/p&gt;
&lt;p&gt;一般走狗君读的书，作者不是死了两千年，至少也有八百年，连渣渣都不剩的那种。所以如果不是禁书，我还真不一定知道它，更不会读。不过既然是禁书，又是历史方面的，那就好玩儿了，他们不想让我知道的，一定是我应该了解的，他越恐惧，我越好奇。&lt;/p&gt;
&lt;p&gt;读完的感觉嘛，确实是本好书，每个人都应该读一下，如果你能找到的话。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Kindle Paperwhite 1代与3代白色版对比</title><link>http://0x3f.org/posts/compare-kindle-paperwhite-v1-and-v3-white/</link><pubDate>Mon, 13 Jun 2016 16:01:00 +0000</pubDate><guid>http://0x3f.org/posts/compare-kindle-paperwhite-v1-and-v3-white/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619161955000-3a260c5a5628c12d7e5ceb987d877478.avif" alt="2020-06-19-16-19-55-20160613002"&gt;&lt;/p&gt;
&lt;p&gt;如果说2代相对于1代的改进微乎其微，3代在屏幕和配置上的升级是效果显著的。&lt;/p&gt;
&lt;p&gt;从原来的212 PPI升级到300PPI，屏幕像素增加了一倍，加上对比度的提升，显示效果相对1代的变化还是相当明显的，文字更加犀利。内存从256M增加到512M，操作流畅度也有较大的提升，尤其是在用输入法的时候，已经可以基本流畅的输入了。&lt;/p&gt;
&lt;p&gt;然而3代刚推出的时候我还是没有换。一方面以上所说的提升和价格的增量并不匹配。另一面，前代在外观和材质上有很大的问题。&lt;/p&gt;
&lt;p&gt;首先是颜色，黑色稍微粘上点灰就很明显，对于像我这样的强迫症患者，擦灰的时间几乎和阅读一样多。另外，前代的背面采用的是磨砂处理，在干净的前提下手感是不错，不过很容易粘灰，而且粘灰后手感很差，最要命的是，磨砂加上黑色就是指纹收集器！&lt;/p&gt;
&lt;p&gt;所以白色版的出现简直就是一次救赎。白色粘灰后并不明显，背板采用颗粒较大、质感较硬的做工，手感比前代好很多。加上前面所说的在阅读体验上的提升，可以升级了。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>读完《史记》</title><link>http://0x3f.org/posts/after-reading-records-of-the-grand-historian/</link><pubDate>Mon, 13 Jun 2016 15:52:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-records-of-the-grand-historian/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619161459000-b5c083ac838e2c7d7e7106b39a7a4132.avif" alt="2020-06-19-16-14-59-20160613001"&gt;&lt;/p&gt;
&lt;p&gt;之前读通鉴，用了四年，这次用了七个月。终于是名正言顺的两司马门下走狗了，哦耶。&lt;/p&gt;
&lt;p&gt;史记这本书，说到底还是个人修史，主观性是很大的。因为坐李陵案，司马迁是有悲愤的情结的，所以他特别喜欢悲剧英雄，很多名篇都是写这种人的抒情散文，比如《屈原贾谊列传》、《项羽本纪》。主观的爱憎过多，一定会失之客观。所以项羽以一暴君成垓下悲歌，刘邦以一英主成千古屌丝。褒贬无需作假，有所取舍足矣。&lt;/p&gt;
&lt;p&gt;另外，史料的真实性是值得商榷的。因为秦始皇的焚书坑儒，六国史书尽毁，司马迁的史料来源驳杂，有些事情甚至不同章节互相矛盾。比如黄池之会，左传就只说「遂长吴国」，史记也是照抄这句，究竟晋吴谁做了盟主，还是有争议的。&lt;/p&gt;
&lt;p&gt;史记的成功，在于司马迁的文采和宏观的大体真实。鲁迅说它是无韵之离骚，因为司马迁用了大量小说家的笔法写文章。比如讲齐威王的一生，说此人继位后，好为淫乐长夜之饮，诸侯交侵，相声演员淳于髡看不下去了，跟威王说，我听说国中飞来一只大鸟，三年不飞，三年不鸣，你说这是肿么了？威王说，这只鸟啊，三年不飞，一飞冲天，三年不鸣，一鸣惊人。于是罢饮宴，召集大臣，杀一人，赏一人，全国肃然。然后发兵四境，夺回失地，齐国大振。了了几十字，摇人心旌。&lt;/p&gt;
&lt;p&gt;然而史实肯定不是这么简单，戏剧之所以好看，就在于它将所有出场的人物脸谱化、剧情简单化。比如讲到冒顿单于，主要讲了两件事。&lt;/p&gt;
&lt;p&gt;第一件是鸣镝弑父。依次射野兽、爱马、爱妾、单于坐骑，确保鸣镝已有足够的威信，然后完成致命一击。&lt;/p&gt;
&lt;p&gt;第二件是击灭东胡。东胡利用冒顿刚继位的时机，来索要千里马。冒顿召集臣属商量，都说马是游牧民族的命，不能给。冒顿说，不能因为一匹马让大家冒生命的危险，妥协了。然后东胡又来要冒顿的媳妇儿，冒顿如法炮制。最后东胡说，有块废地也给我们吧。当大家都说反正是废地给就给了的时候，冒顿拍案而起，说土地是国家根本，虽废地寸土必争，然后发兵突袭东胡，一举成功。&lt;/p&gt;
&lt;p&gt;把历史戏剧化，这就是史记好看的地方。马未都先生说，历史没有真相，只残存一个道理。对于大部分人来说，历史细节的真相并不重要，大框架对就可以了，宏观层面的东西足以让人受益匪浅，追本溯源的事留给专业做学问的就好。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>「食其」是什么？</title><link>http://0x3f.org/posts/what-is-yi-ji/</link><pubDate>Mon, 06 Jun 2016 16:48:00 +0000</pubDate><guid>http://0x3f.org/posts/what-is-yi-ji/</guid><description>&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/xbot/image-hosting/master/blog/20200619160723000-adf7dfe3181f10bb721e7aa00caacf18.avif" alt="2020-06-19-16-07-23-20160606001"&gt;&lt;/p&gt;
&lt;p&gt;「食其」音「异基」，人名。&lt;/p&gt;
&lt;p&gt;读汉初的历史，有三个人都叫这个名字：郦食其、审食其和赵食其。这似乎在当时是个很流行的名字，俨然就是汉代的丽丽、芳芳啊。&lt;/p&gt;
&lt;p&gt;这两个字为什么念这个音？又是什么意思？&lt;/p&gt;
&lt;p&gt;《康熙字典》里只是明确了两个字的读音，并没有解释和考证出处。&lt;/p&gt;
&lt;p&gt;《史记索隐》说：「食音异。郦、审、赵三人同名，其音合并同，以六国时卫有司马食其，并慕其名。」意即出自战国时卫国司马食其，后人因为仰慕此人，就取他的名字来用。此外比如司马相如因为仰慕蔺相如而改名也是一例，宋人王楙在《野客丛书》里也持这个观点。&lt;/p&gt;
&lt;p&gt;也有人说出自子路所说「食其食者不避其难」。子路做卫国贵族孔悝的家宰时，卫国发生政变，孔悝被劫持，子路听说后只身赴难，在打斗过程中帽子被打掉，说「君子死，冠不免」，在丢下兵器扶帽子的时候被杀。子路去救孔悝时说的这句话，简单说就是吃人嘴短。然而食字在发yi音时并没有吃的意思，所以这种说法当是附会。&lt;/p&gt;
&lt;p&gt;比较来看，《史记索隐》的说法最靠谱，但是也没有从根本上解释清楚这个名字的意思。不过考虑到先秦人名普遍比较朴拙和文、言异路的因素，这个名字应该出自当时的口语或方言，只是写到书上时拿「食其」两个字做假借。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;本期封面&lt;/strong&gt;：我的贝克利要🌼了&lt;/p&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>两司马门下走狗创刊号</title><link>http://0x3f.org/posts/the-first-post-of-running-dog/</link><pubDate>Mon, 06 Jun 2016 16:22:00 +0000</pubDate><guid>http://0x3f.org/posts/the-first-post-of-running-dog/</guid><description>&lt;p&gt;算是开始玩自媒体了么？&lt;/p&gt;
&lt;p&gt;如果从写博客算起，十年前就算了。从一开始和大多数人一样，把博客当成公开日记写，到后来很快明白博客的定位，我的自媒体时代很快从0.1升级到1.0。&lt;/p&gt;
&lt;p&gt;后来，因为博客托管网站的所见即所得编辑器生成的HTML代码格式太死板，自己定义了一套简单的标记，然后写了个转换程序，然而没过多久就发现，已经有了类似的东西&amp;ndash;轻量型标记语言。&lt;/p&gt;
&lt;p&gt;很快，托管的服务已经不能满足个性化要求。自然而然地，就有了独立博客。这算是我的自媒体2.0时代吧。&lt;/p&gt;
&lt;p&gt;就这样一直持续了很多年。内容基本上是日常的总结和笔记，总之是给自己看的成分居多。&lt;/p&gt;
&lt;p&gt;公众号怎么定位呢？首先应该是写给别人看的，所以不能过于自由，想什么时候写什么时候写，有时候一月一次，有时候一月几次，有时候几个月不来一次（😱）。其次应该是个专栏，所以主题应该集中，不能想写什么写什么。&lt;/p&gt;
&lt;p&gt;那么写点啥呢？在一个理工宅少得可怜的爱好里，翻翻故纸堆是唯一比较能算得上文艺的东西了。其实在接触电脑之前，我一直是想学考古的（💀），现在看来其实人还是最好不要忘了初心（😳）。&lt;/p&gt;
&lt;p&gt;好了，都闪开，我要进（kai）入（shi）3.0时（zhuang）代（bi）了！&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文最早发布在公众号：&lt;strong&gt;两司马门下走狗&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://0x3f.org/images/qrcode_zougou.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Kindle Lazybones: Control Kindle From Your Phone</title><link>http://0x3f.org/posts/kindle-lazybones/</link><pubDate>Mon, 06 Jun 2016 10:33:00 +0000</pubDate><guid>http://0x3f.org/posts/kindle-lazybones/</guid><description>&lt;h1 id="kindle-lazybones"&gt;Kindle Lazybones&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt; .-. _
( `. .' )
`\ ` .'
| |
| |
| 66|_
| ,__)
|(,_|
| |
| \_,
| |
| |
.' \
( , )
'--' '-'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remote controlling utilities for Kindle.&lt;/p&gt;
&lt;h2 id="feature"&gt;Feature&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Flip over Kindle with your smartphone.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="issues"&gt;Issues&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Currently only Kindle PaperWhite is supported, PW2/PW3 are not yet.&lt;/li&gt;
&lt;li&gt;Kindle still goes to sleep after 10 minutes, a temporary solution is running the searchbox command &lt;code&gt;~ds&lt;/code&gt; to disable screensaver, but only a restart can resume it. The other way is changing 10 minutes to longer by modifying &lt;code&gt;/etc/kdb/system/daemon/powerd/t1_timeout&lt;/code&gt;, but it&amp;rsquo;s readonly although I&amp;rsquo;ve run &lt;code&gt;mntroot rw&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Button sizes won&amp;rsquo;t be adjusted correctly when the orientation of Android smartphones changes (&lt;em&gt;from landscape to portrait or vice versa&lt;/em&gt;), a temporary solution is refreshing the page. iOS devices don&amp;rsquo;t have this problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="project-architechture"&gt;Project Architechture&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;kindle/ Server-side files for Kindle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="user-guide"&gt;User Guide&lt;/h2&gt;
&lt;h3 id="jailbreak-kindle"&gt;Jailbreak Kindle&lt;/h3&gt;
&lt;p&gt;Jailbreaking Kindle allows you to access its operating system.&lt;/p&gt;</description></item><item><title>奇怪的决战</title><link>http://0x3f.org/posts/a-strange-decisive-battle/</link><pubDate>Sun, 01 May 2016 10:59:00 +0000</pubDate><guid>http://0x3f.org/posts/a-strange-decisive-battle/</guid><description>&lt;p&gt;前两天读史记王翦列传，觉得秦楚的决战很奇怪。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;王翦果代李信击荆。荆闻王翦益军而来，乃悉国中兵以拒秦。王翦至，坚壁而守之，不肯战。荆兵数出挑战，终不出。王翦日休士洗沐，而善饮食抚循之，亲与士卒同食。久之，王翦使人问军中戏乎？对曰：「方投石超距。」于是王翦曰：「士卒可用矣。」荆数挑战而秦不出，乃引而东。翦因举兵追之，令壮士击，大破荆军。至蕲南，杀其将军项燕，荆兵遂败走。秦因乘胜略定荆地城邑。岁余，虏荆王负刍，竟平荆地为郡县。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;稍微有点军事常识就知道，防守方最好的办法是坚守不战，在自己的地盘上，对方的后勤补给要比自己困难得多，一旦补给不继，军心必乱，势必撤兵，这时候再追上去打，胜算很大，也就是所谓以逸待劳。比如秦赵长平之战，一开始，廉颇先用小股部队跟秦军接触，一看打不赢，马上收缩防线，避免决战，搞得秦军进也不是、退也不是，军力损耗极大，不得以只好用反间换掉廉颇。&lt;/p&gt;
&lt;p&gt;所以战争中的进攻方是处于劣势的，要扭转不利的态势，就要把主动权握在自己手里，所以一般会用反客为主的办法。虽然我是进攻方，但我不著急进攻你，让你自己沈不住气来打我，这时候攻守易形，我成了防守方，你成了进攻方，形势就对我有利了。&lt;/p&gt;
&lt;p&gt;所以王翦反客为主是正常的，项燕急著打就很奇怪了。老项家累世将门，项燕沙场宿将，不可能连常识都不懂。&lt;/p&gt;
&lt;p&gt;也许唯一合理的解释是楚国国力衰败，撑不下去了。&lt;/p&gt;
&lt;p&gt;以前秦国伐楚很困难，因为楚国西有江汉之险，北有诸夏扞蔽。不过自白起破鄢郢，江汉天险尽失；自三晋覆灭，中原逐鹿之势已成。秦国伐楚，后勤补给已经不是问题。&lt;/p&gt;
&lt;p&gt;另外，让秦国拥有支持百万级灭国战役能力的，还有伐蜀的决策。自商君变法，秦国势平地起飞，此后相当长的一段时间，秦国虽说是战国首强，但也不能占据压倒性的优势，直到秦灭六国前的三十年，还有信陵君收天下之兵扣关攻秦的事。战争不是战斗，决定成败的主要还是国力。李信的二十万大军覆灭后，秦国可以马上再把六十万人送上前线，这个国力，不赢没有天理。所以司马错论伐蜀，同时拥有关中、蜀中两块天府之国，是秦国国力质变的关键。&lt;/p&gt;
&lt;p&gt;这个时候的楚国，已经是冢中枯骨。在秦国连年的攻势下，大片国土沦丧，鄢郢破而迁陈，三晋亡而迁寿春，几十年间，颠沛流离，没有喘息的机会，靠吃战略纵深的老本苟延残喘。所以在这次决战之前，可能国力已经难以为继了，但是楚国自己也知道八百年国运系于这一战，所以不得不起倾国之兵应战。空虚的国力和浩大的战争消耗最终迫使项燕选择速战速决，战还有一线生机，不战只能坐以待毙。&lt;/p&gt;</description></item><item><title>Alfred-pushbullet: Push a text to your phone</title><link>http://0x3f.org/posts/alfred-pushbullet/</link><pubDate>Wed, 13 Apr 2016 17:30:00 +0000</pubDate><guid>http://0x3f.org/posts/alfred-pushbullet/</guid><description>&lt;p&gt;Pushbullet workflow for Alfred.&lt;/p&gt;
&lt;h2 id="features"&gt;Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Push a text to another device.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installation"&gt;Installation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Download the latest release and rename it to pushbullet.alfredworkflow.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Double click it to import it into Alfred.&lt;/li&gt;
&lt;li&gt;Double click the &amp;ldquo;Run Script&amp;rdquo; button and replace &amp;ldquo;ACCESS_TOKEN&amp;rdquo; and &amp;ldquo;DEVICE_NAME&amp;rdquo; according to your pushbullet settings.&lt;/li&gt;
&lt;li&gt;Activate alfred and input &amp;ldquo;push blablabla&amp;rdquo;, then press enter.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="author"&gt;Author&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;base64decode IkRvbmllIExlaWdoIiA8ZG9uaWUubGVpZ2hAZ21haWwuY29tPgo=&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="download"&gt;Download&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/alfred-pushbullet/"&gt;https://github.com/xbot/alfred-pushbullet/&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Linux下做Mac OSX安装U盘的步骤</title><link>http://0x3f.org/posts/create-mac-bootable-usb-stick-on-linux/</link><pubDate>Tue, 08 Mar 2016 12:22:00 +0000</pubDate><guid>http://0x3f.org/posts/create-mac-bootable-usb-stick-on-linux/</guid><description>&lt;p&gt;假设U盘对应/dev/sdb1、OSX安装包是osx.dmg。整个过程就是提取出一系列文件，然后复制到U盘里。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 格式化U盘为hfs+文件系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkfs.hfsplus -v EICaptianInstall /dev/sdb1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 提取和挂载第一个光盘镜像&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dmg2img -p &lt;span class="m"&gt;5&lt;/span&gt; osx.dmg osx.img
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir raw &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo mount -o loop osx.img raw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 提取和挂载第二个光盘镜像&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dmg2img -p &lt;span class="m"&gt;5&lt;/span&gt; raw/Install&lt;span class="se"&gt;\ &lt;/span&gt;OS&lt;span class="se"&gt;\ &lt;/span&gt;X&lt;span class="se"&gt;\ &lt;/span&gt;El&lt;span class="se"&gt;\ &lt;/span&gt;Capitan.app/Contents/SharedSupport/InstallESD.dmg InstallESD.img
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir esd &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo mount -o loop InstallESD.img esd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 提取和挂载第三个光盘镜像&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dmg2img -p &lt;span class="m"&gt;4&lt;/span&gt; esd/BaseSystem.dmg BaseSystem.img
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir base &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo mount -o loop BaseSystem.img base
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 挂载U盘&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir usb &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo mount /dev/sdb1 usb
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 复制一系列文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp -r base/* usb/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm usb/System/Installation/Packages
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp -r esd/Packages usb/System/Installation/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp esd/BaseSystem.* usb/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意dmg2img的参数-p表示提取dmg的第几个分区，似乎不同的OSX版本提取哪个分区也不一样，判断方法就是先执行&lt;code&gt;dmg2img osx.dmg&lt;/code&gt;，看哪个分区提取得最慢就选哪个。&lt;/p&gt;</description></item><item><title>FastFold：Vim折叠功能的救赎</title><link>http://0x3f.org/posts/fastfold-for-vim/</link><pubDate>Wed, 24 Feb 2016 11:06:00 +0000</pubDate><guid>http://0x3f.org/posts/fastfold-for-vim/</guid><description>&lt;p&gt;设置Vim的折叠规则为syntax存在两个问题。一是如果源码中有大量折叠区域，在插入模式中输入会变得很卡。二是刚输入一个折叠区域的起始符号，后面所有的折叠都会被打开。&lt;/p&gt;
&lt;p&gt;第一个问题是因为Vim的syntax折叠规则处理过于低效。而后一个问题对于所有自动折叠规则都会存在，原因是Vim对折叠的更新过早。&lt;/p&gt;
&lt;p&gt;传统的解决办法是将折叠规则置为manual，并在合适的时机重置为syntax或其它相应规则。但是工作繁复而且往往问题很多。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/Konfekt/FastFold"&gt;FastFold&lt;/a&gt;是遵循上面所说的方法解决这些问题的插件，不过默认会在所有与折叠相关的时机更新折叠，会导致相关的操作变慢，例如zc和zo时都会有明显的卡顿。鉴于其它时机对折叠的更新已经足够及时，可以通过配置取消受在到明显影响的时机更新折叠：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; FastFold只在za/zA/zx/zX时更新折叠信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;fastfold_fold_command_suffixes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; [&lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;X&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>FZF: 又一个文件模糊查询工具</title><link>http://0x3f.org/posts/fzf-yet-another-fuzzy-finder/</link><pubDate>Mon, 01 Feb 2016 11:42:00 +0000</pubDate><guid>http://0x3f.org/posts/fzf-yet-another-fuzzy-finder/</guid><description>&lt;p&gt;&lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt;是个独立的命令行工具，索引速度很快，可以通过&lt;a href="https://github.com/junegunn/fzf.vim"&gt;fzf-vim&lt;/a&gt;配合使用。&lt;/p&gt;
&lt;h2 id="特性"&gt;特性&lt;/h2&gt;
&lt;p&gt;功能支持还是比较全的：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;List&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Files [PATH]&lt;/td&gt;
&lt;td&gt;Files (similar to &lt;code&gt;:FZF&lt;/code&gt; )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitFiles&lt;/td&gt;
&lt;td&gt;Git files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buffers&lt;/td&gt;
&lt;td&gt;Open buffers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Colors&lt;/td&gt;
&lt;td&gt;Color schemes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ag [PATTERN]&lt;/td&gt;
&lt;td&gt;{ag}{5} search result (ALT-A to select all, ALT-D to deselect all)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines&lt;/td&gt;
&lt;td&gt;Lines in loaded buffers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BLines&lt;/td&gt;
&lt;td&gt;Lines in the current buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tags&lt;/td&gt;
&lt;td&gt;Tags in the project ( &lt;code&gt;ctags -R&lt;/code&gt; )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BTags&lt;/td&gt;
&lt;td&gt;Tags in the current buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marks&lt;/td&gt;
&lt;td&gt;Marks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Locate PATTERN&lt;/td&gt;
&lt;td&gt;&lt;code&gt;locate&lt;/code&gt; command output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;History&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v:oldfiles&lt;/code&gt; and open buffers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;History:&lt;/td&gt;
&lt;td&gt;Command history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;History/&lt;/td&gt;
&lt;td&gt;Search history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snippets&lt;/td&gt;
&lt;td&gt;Snippets ({UltiSnips}{6})&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commits&lt;/td&gt;
&lt;td&gt;Git commits (requires {fugitive.vim}{7})&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BCommits&lt;/td&gt;
&lt;td&gt;Git commits for the current buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commands&lt;/td&gt;
&lt;td&gt;Commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maps&lt;/td&gt;
&lt;td&gt;Normal mode mappings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Helptags&lt;/td&gt;
&lt;td&gt;Help tags [1]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="结论"&gt;结论&lt;/h2&gt;
&lt;p&gt;fzf需要在终端中执行，在vim中使用时需要另外启动一个xterm实例，UI的割裂感很强，而且xterm本身的操性你懂的。另外Tags模式需要两次回车。所以暂不会用它取代ctrlp和unite。&lt;/p&gt;</description></item><item><title>ctags vs gtags vs phpctags</title><link>http://0x3f.org/posts/ctags-vs-gtags-vs-phpctags/</link><pubDate>Fri, 29 Jan 2016 17:55:00 +0000</pubDate><guid>http://0x3f.org/posts/ctags-vs-gtags-vs-phpctags/</guid><description>&lt;p&gt;这两天把源码分析工具从ctags向gtags迁移，另外尝试了一下phpctags。&lt;/p&gt;
&lt;p&gt;之前用ctags有两个问题，一个是如果同一tag有多个定义，按Ctrl+]只能跳转到第一处。另一个是用cscope查询tag的调用记录时，有些tag查不到结果。&lt;/p&gt;
&lt;p&gt;几年前接触过gtags，因为当时还不支持宇宙最好语言，所以没用。这次测试了一下，前面两个ctags的问题都可以解决。&lt;/p&gt;
&lt;p&gt;安装后需要手工拷贝gtags.vim和gtags-cscope.vim到vim的plugin目录，然后配置如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;Gtags_Close_When_Single&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;Gtags_Auto_Update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;cscope_silent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;cpp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;javascript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;go&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;]&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="nx"&gt;Gtags&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;cpp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;javascript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;go&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;[&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="nx"&gt;Gtags&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;]&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="k"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Unite gtags/def:&amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;cword&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;[&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="k"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Unite gtags/ref:&amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;cword&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其它选项参见前面两个文件里的注释。&lt;/p&gt;
&lt;p&gt;另外尝试了一下phpctags，据说和ctags兼容并对php做了优化。实际使用效果和ctags没发现有什么区别，不过tagbar-phpctags倒是比tagbar用ctags时效果更好。&lt;/p&gt;</description></item><item><title>CtrlP vs Unite vs Command-T vs FuzzyFinder</title><link>http://0x3f.org/posts/ctrlp-vs-unite-vs-command-t-vs-fuzzyfinder/</link><pubDate>Wed, 27 Jan 2016 16:16:00 +0000</pubDate><guid>http://0x3f.org/posts/ctrlp-vs-unite-vs-command-t-vs-fuzzyfinder/</guid><description>&lt;h2 id="简述"&gt;简述&lt;/h2&gt;
&lt;p&gt;Sublime在文件打开速度上的表现很惊艳，Vim有几个扩展可以实现类似功能，本文对这些扩展做个对比。&lt;/p&gt;
&lt;p&gt;虽然每个扩展都或多或少地实现了一些功能，我个人用得最多的也就文件、Tag、Buffer Tag的模糊查找这三个，像MRU、buffer之类的查找不觉得有多大用处，所以提高工作效率的工具一定是在热度环节有很好表现，其余偏门功能可以交给插件实现，在这点上CtrlP和Unite做得很好。所以下面针对最常用的这三个功能做下对比，更多功能的对比见下表：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/FhDLWLYr/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="文件模糊查找"&gt;文件模糊查找&lt;/h2&gt;
&lt;p&gt;Command-T的文件索引速度最快，各方面在这几个扩展中的表现都是最好的。&lt;/p&gt;
&lt;p&gt;CtrlP默认使用VIM自建的globpath()，需要手工配置使用&lt;a href="https://github.com/ggreer/the_silver_searcher"&gt;ag&lt;/a&gt;以获取更快的速度，据说使用find命令效率更高，实际感觉和ag差别不大。&lt;/p&gt;
&lt;p&gt;Unite也需要手工设置使用ag，而且可以实现异步索引，在这一点的体验上好于前两个，但是在模糊匹配的排序上表现不好，比如输入“php”，当然希望“/etc/php.ini”这样的结果排在“/home/peter/host/tmp.txt”前面，实际往往不是这样，Unite的几个sorter里，数rank的排序结果最接近于这个要求，但是表现仍然不如前两个。&lt;/p&gt;
&lt;h2 id="tag模糊查找"&gt;Tag模糊查找&lt;/h2&gt;
&lt;p&gt;三个扩展都是通过ctags实现，虽然Unite的排序问题仍然存在，对于Tag这么简短的东西，问题不大。&lt;/p&gt;
&lt;h2 id="buffer-tag模糊查找"&gt;Buffer Tag模糊查找&lt;/h2&gt;
&lt;p&gt;CtrlP的表现是最好的。&lt;/p&gt;
&lt;p&gt;Unite需要通过unite-outline这个source实现，但是只能列出类和方法，无法定制列举类型。而且默认选中排在第一位的类名，查询方法时很不方便。&lt;/p&gt;
&lt;p&gt;Command-T不支持此功能。&lt;/p&gt;
&lt;h2 id="我的选择"&gt;我的选择&lt;/h2&gt;
&lt;p&gt;FuzzyFinder是该类扩展里的老前辈，不过早已不维护，功能上不比其它几个出彩。Command-T虽然在文件索引速度上表现最好，但是优势并不很明显，而且支持功能最少。所以排除这两个。&lt;/p&gt;
&lt;p&gt;在最常用的三个功能上，CtrlP的综合表现是最均衡的，所以留下它。Unite本身是一种统一的交互方式和界面，很多扩展（source）可以实现五花八门的功能，像unite-outline虽然在Buffer Tag上表现不佳，对于Markdown和Vim文档还是很有用的。&lt;/p&gt;
&lt;h2 id="update-2016-02-01"&gt;Update: 2016-02-01&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://0x3f.org/post/fzf-yet-another-fuzzy-finder/"&gt;FZF: 又一个文件模糊查询工具&lt;/a&gt;&lt;/p&gt;</description></item><item><title>简化Vim Addons Manager安装扩展的操作</title><link>http://0x3f.org/posts/simplify-vim-addon-installation-issues/</link><pubDate>Wed, 20 Jan 2016 18:05:00 +0000</pubDate><guid>http://0x3f.org/posts/simplify-vim-addon-installation-issues/</guid><description>&lt;p&gt;相对Sublime的Package Control，VAM安装和卸载扩展的操作很烦琐。以下脚本在安装完扩展后自动注册，无须手工添加到vimrc，另外增加命令:UninstallAddons，从注册表中删除扩展。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;runtimepath&lt;/span&gt;&lt;span class="p"&gt;+=~&lt;/span&gt;&lt;span class="sr"&gt;/.vim/&lt;/span&gt;&lt;span class="nx"&gt;addons&lt;/span&gt;/&lt;span class="nx"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;addon&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;active_addons&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;/.vim/vam_registry&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;filereadable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;active_addons&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;vam&lt;/span&gt;#&lt;span class="nx"&gt;ActivateAddons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;active_addons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Addon post-install hook.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;MyAddonPostActivateHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pluginDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;filereadable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;regLines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regLines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;repository&lt;/span&gt;.&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regLines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;uniq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regLines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;regLines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; [&lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;repository&lt;/span&gt;.&lt;span class="nx"&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;writefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regLines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;endfun&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;vim_addon_manager&lt;/span&gt;.&lt;span class="nx"&gt;post_install_hook_functions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; [&lt;span class="s1"&gt;&amp;#39;MyAddonPostActivateHook&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Complete the addon name.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;MyDoActivatedAddonsCompete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;...&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fullList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;vim_addon_manager&lt;/span&gt;.&lt;span class="nx"&gt;activated_plugins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fullList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;v:val =~ &amp;#34;.*&amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;.*&amp;#34;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fullList&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;endfun&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Remove records of addons from the registry.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;MyUninstallAddons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;...&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;filereadable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;regLines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Registry is empty.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;addonName&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="m"&gt;000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regLines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addonName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regLines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;addonName&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39; is removed from the registry.&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;addonName&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39; cannot be found in the registry.&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;writefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regLines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;:&lt;span class="nx"&gt;vamRegistryFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;endfun&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;customlist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;MyDoActivatedAddonsCompete&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;nargs&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;* &lt;span class="nx"&gt;UninstallAddons&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;MyUninstallAddons&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>BiuBiu: A Chrome Extension Blocking AJAX Requests</title><link>http://0x3f.org/posts/chrome-extension-biubiu/</link><pubDate>Thu, 31 Dec 2015 14:19:00 +0000</pubDate><guid>http://0x3f.org/posts/chrome-extension-biubiu/</guid><description>&lt;h1 id="biubiu"&gt;BiuBiu&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;BiuBiu&lt;/strong&gt; is an extension for Google Chrome Browser which intends to make life easier for debugging and profiling.&lt;/p&gt;
&lt;p&gt;For now, it only blocks AJAX requests made by JQuery, more features may be added in the future.&lt;/p&gt;
&lt;h2 id="features"&gt;Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Toggle to enable or disable BiuBiu.&lt;/li&gt;
&lt;li&gt;Block requests made by JQuery by URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="author"&gt;Author&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Donie Leigh &amp;lt;donie.leigh at gmail.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="links"&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Project: &lt;a href="https://github.com/xbot/chrome-biubiu"&gt;https://github.com/xbot/chrome-biubiu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="faq"&gt;FAQ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;ndash;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ndash;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="change-log"&gt;Change Log&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;version 1.0.1 (2015-12-31)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fix the complaining when there is no jQuery or jQuery.cookie.js loaded in the injected page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;version 1.0.0 (2015-12-30)&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>读完《春秋左传注》</title><link>http://0x3f.org/posts/after-reading-zuo-zhuan/</link><pubDate>Sun, 15 Nov 2015 18:24:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-zuo-zhuan/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/F6y8YsUg/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;读这本书，用了一年时间。前面读《通鉴》，用了四年，平均一年五本书的节奏，读尽相斫书的伟大理想不知道这辈子能不能实现了。汉以后的书都好读，也不一定。&lt;/p&gt;
&lt;p&gt;总结一下，主要有两个心得吧。一个是梳理了一下春秋的脉络，把以前知道的片断都连了起来，抓住“蛮夷与戎狄交，中国不绝若线”的大背景，整个春秋时代大家都忙啥呢就清楚了，然后分成三段看，齐桓始霸、晋楚争霸、吴越争霸，比从五巨头切入清晰。第二个是加深了对礼乐文化的认识，贵族时代干啥都跟闹著玩似的，反映出我们屌丝的世界太低俗，整本《诗经》就是贵族圈的黑话，搞得我老想叉开去读《诗经原始》，剁手剁手，不然更看不完了。&lt;/p&gt;
&lt;p&gt;读《通鉴》算是用通史贯穿一下脉络，《左传》是第一本读完的断代史，本来想接著读《战国策》，看了一眼，文章写得太烂，又是纵横家的书，所以直接读《史记》，司马迁的小说写得还是不错的，迁儿哥，我来了！&lt;/p&gt;</description></item><item><title>寻找失落的匈奴（201409）</title><link>http://0x3f.org/posts/a-trip-to-tongwan-city/</link><pubDate>Thu, 20 Aug 2015 23:07:00 +0000</pubDate><guid>http://0x3f.org/posts/a-trip-to-tongwan-city/</guid><description>&lt;h2 id="行程"&gt;行程&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvkFOn/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="d1am-失落的匈奴"&gt;D1.AM 失落的匈奴&lt;/h2&gt;
&lt;p&gt;匈奴是中国统一后的第一个大敌，极盛时号称控弦四十万，以至于汉武帝穷高、文、景三代积蓄，鏖战数十年，延及元帝，郅支授首，才终于换来一句“犯强汉者，虽远必诛”。&lt;/p&gt;
&lt;p&gt;东汉招引外族入居内地，想同化并加以利用，至于魏晋，欺压各族，又不加防备。&lt;/p&gt;
&lt;p&gt;西晋初年，由封建制的复兴导致的八王之乱，纷纭十六年，耗尽了皇族势力。被压制已久的民族矛盾于是爆发，匈奴、鲜卑、羯、氐、羌五族先后建立十六个国家，混战一百三十多年，史称五胡十六国。&lt;/p&gt;
&lt;p&gt;其中，匈奴铁弗部赫连勃勃建立大夏国，横行秦晋，役民十万蒸土筑城，号统万城。蒸土就是在土中混入生石灰，然后浇水夯筑，所以城墙是白色的，当地人至今都叫白城子。筑城要求极为严格，工程验收人以铁锥刺墙，刺入一寸杀筑者，尸体填入城墙，所以城墙极为坚固，是夯土建筑的巅峰之作。后来北魏太武帝拓跋焘灭夏入城，说“统驭万邦，在德不在险”。&lt;/p&gt;
&lt;p&gt;统万城遗址在陕西靖边。我喜欢去这种没有被过度商业化开发的地方，再过几年，也许就再也见不到这种荒草孤城的景象了。&lt;/p&gt;
&lt;p&gt;早上四点火车到站，车站门口有很多黑车，会漫天要价，事先做好功课就不会被宰，议定一百五，要说明白包往返，到地方等两个小时。&lt;/p&gt;
&lt;p&gt;路上停车吃洋芋擦擦，就是炒土豆丝……&lt;/p&gt;
&lt;p&gt;火车站到统万城大概三十公里，所以不会用太长时间，五点多到的时候，天还没有亮，这个时候没人收费，可以直接开进去。&lt;/p&gt;
&lt;p&gt;天色微亮，从停车场走向统万城还是条土路。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvl0fd/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;遗址正在进行小规模的修复。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvllZw/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城墩填充的外表被刻画成砖的样子，而夯土建筑的轮廓应该是一层一层的。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvm6r1/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;像这样：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvldId/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;走在质地坚硬的城墙上，可以想象当年它曾是怎样的坚不可摧。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvkzhJ/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;凸出的城墩和城墙形成有纵深的防御体系，可以分割敌人的阵形，将攻城者置于被三面夹击的死地。残存的城墙尚且这么高，不知道当年是如何雄伟的一座城！&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvlIDl/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;荒原晨露，日出统万。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvlUtR/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;沿着小路走向城中的高台，沙深露重，很不好走。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvmi41/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;土墩离外城城门不远，可能是内城的一部分。高处的洞里，栖满了野鸽子。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvnx9o/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城的中部，据说是宫殿遗址。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvmz3v/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城北一处正在发掘的现场。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvn3QQ/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvneNw/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;北角的城墩，淹没在一望无际的荒草中。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvmaU4/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我在这里休息，读完了《晋书·赫连勃勃载记》。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvmzWn/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;东角的城墩已经破坏得快消失了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvnUug/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;回望城内。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvnwvY/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;东南城墙已经快消失在荒草中了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvoha5/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;南角墩曾被挖做窑洞。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvo0as/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;只有西角残存的遗迹最完整。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvokDG/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;因为去得早，而且遗址少有人去，所以整个早上只有我一个人，不紧不慢地走遍全城，用了三个小时，好在司机没有催我，如果能带着帐篷来这里扎营，重读通鉴永嘉南渡后三百年的烽火狼烟，一定很刺激，不过可能再也没有机会了。&lt;/p&gt;
&lt;h2 id="d1pm-龙洲丹霞波浪谷"&gt;D1.PM 龙洲丹霞（波浪谷）&lt;/h2&gt;
&lt;p&gt;从统万城出来，时间还很早，上车直奔龙洲丹霞，车上议价，往返加等待，100￥。&lt;/p&gt;
&lt;p&gt;路上还有一段长城的遗迹，只剩下垄起的一条痕迹，可能是汉长城。&lt;/p&gt;
&lt;p&gt;景区已经修了观景台和公路，不过还没有收费。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvowH1/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;看这个就知道为什么叫波浪谷了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvp1kO/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;下面是深沟，岩石表面是风化的沙土，走在上面很惊险。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvoS6y/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;靖边有石油，能看到远方油井喷出的火。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvqhys/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;其它地方见到的丹霞都是在地上的，这里是在地下，要从公路边的野路下去，所以找个知道路口在哪的司机很重要。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvq1Sq/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;有的小路不好走，只能手脚屁股并用。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvpYcF/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;下到谷底。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvqTNE/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;很美，真的很美。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ETlvqwT5/medish.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>自驾鸡鸣驿、草沿天路（201507）</title><link>http://0x3f.org/posts/a-drive-to-jimingyi-and-caoyantianlu/</link><pubDate>Wed, 12 Aug 2015 21:05:00 +0000</pubDate><guid>http://0x3f.org/posts/a-drive-to-jimingyi-and-caoyantianlu/</guid><description>&lt;h2 id="行程"&gt;行程&lt;/h2&gt;
&lt;p&gt;D1：上午，北京到怀来，土木之变战场遗址和鸡鸣驿；下午，宣化，清远楼、镇朔楼、时恩寺、辽代古墓壁画群。&lt;/p&gt;
&lt;p&gt;D2：草沿天路，张北野狐岭入，崇礼桦皮岭出。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gAVZI/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="d1am-土木堡鸡鸣驿"&gt;D1.AM 土木堡、鸡鸣驿&lt;/h2&gt;
&lt;p&gt;虽然起得很早，上京藏线也七点多了，赶上草原音乐节，出城的车巨多，在居庸关前面一段堵了半小时。&lt;/p&gt;
&lt;p&gt;到土木堡的时候已经十点多了，唯一的标志物就是这个路边的牌楼。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79NHiK/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;里面是一片荒地，可能是土木之变的战场遗址。当年一战，二十万大军覆没，大明精锐尽丧，英宗北狩，瓦剌围城。可惜于谦，打赢了北京保卫战，却输掉了夺门之变。所以老子说：“持而盈之，不若其已。揣而群之，不可长保也。金玉盈室，莫能守也。富贵而骄，自遗咎也。功遂身退，天之道也。”，实在是金玉良言，不过知进易，知退难，几千年来，有几个张良？&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79OfPX/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;数百年的烽火狼烟，劫波度尽，谁能想到土木堡真正的被毁发生在本朝。路的另一边就是土木村，据说还有土木堡残存的遗迹，时间关系，没有去看。&lt;/p&gt;
&lt;p&gt;事实证明，沿G110奔鸡鸣驿不是个好选择，路况不太好，大货车很多，应该走高速的。&lt;/p&gt;
&lt;p&gt;城门被修成这样也是醉了，我头回见城门口横着一影壁墙的。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79OrNs/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;反而从城内看城门，才有点儿意思。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79RCp8/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城门口的塑像，后面是驿城博物馆，主要介绍一下驿城的历史。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79R7Ys/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城门要远看才有意境。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79Pjev/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城中主干道旁的戏台，其它地方还有两个，小小的驿城，修那么多戏台干嘛，规划有问题。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gBfya/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;多久没见这种风格的房子了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79PQg2/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;驿城署，现在是一家人的住处，可以进去参观，有人剪票，不过里面什么都没有。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79PEKD/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;文昌宫，当年是驿城的学校。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gBzkj/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gCefk/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gCA3P/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;晴耕雨读，用的残体字……&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79QVTE/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;龙神庙里也有个戏台，得是多喜欢看戏！&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gCYi2/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gCPGw/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gDp9U/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gDFPM/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gDWvv/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;范家大院，庚子国变慈禧逃跑时曾在这住了一宿，现在也就剩这么一进。敢向全世界宣战的只有两个人，一个是天朝圣母皇太后，一个是巴格达迪。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79Rc4U/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79WPrE/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79X088/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79Y5Dx/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;伏瞰驿城，怀疑原来真有这么大么，似乎和西夏黑水城和统万城差不多。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79RmQX/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;坐在城头等日落。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79VLis/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我怀疑这城墙是做旧，明朝以后，大多数城墙已经换用砖石结构，应该不会用这种过时的夯土建筑了吧。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gER7v/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79VdOs/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城外的鸡鸣山形态突兀，很显眼，如果是下雨的天气，真有“风雨如晦，鸡鸣不已”的感觉。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79UKXP/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城外不知道为什么弄了几截绿皮火车，很不搭。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gEvHp/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gEU73/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="d1pm-宣化古城辽代古墓壁画"&gt;D1.PM 宣化古城、辽代古墓壁画&lt;/h2&gt;
&lt;p&gt;从鸡鸣驿出来奔宣化，三点多到，吃莜面窝窝，又叫栲姥姥，据说是当地特色，在电视上见过。蘸着羊肉臊子，味道很不错。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79W3Md/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;清远楼和镇朔楼是宣化古城的标志性建筑，始建于明朝，气势恢宏，不可不看。&lt;/p&gt;
&lt;p&gt;清远楼是钟楼，在维修。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7gFvcj/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;镇朔楼是鼓楼，门票5￥，我包场。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79Yayj/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES7r6M4C/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79YOt6/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;一层是个展厅，居然是介绍宣化当代发展的。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ES79YHMf/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;二楼很空，只有一面大鼓。&lt;/p&gt;</description></item><item><title>变形金刚：电影4领袖级大黄蜂</title><link>http://0x3f.org/posts/tf-m4-leader-class-bumble-bee/</link><pubDate>Sat, 01 Aug 2015 18:30:00 +0000</pubDate><guid>http://0x3f.org/posts/tf-m4-leader-class-bumble-bee/</guid><description>&lt;p&gt;当电影2那堆玩具已经成为神物，入个4的L级大黄蜂也未尝不是一种自我安慰。&lt;/p&gt;
&lt;p&gt;电影4的L级BB是3的同模异涂，但是阉割了武器背包，也就是说，这货没有声光效果！虽然3的背包很鸡肋，但是本著先看有没有，再看好不好的原则，4的玩具再一次见证了大缩水时代，我不敢想下一代会做成什么样。多么怀念那个连D级玩具都远超现在L级的时代。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ER427t8F/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;虽然电影2的U级和战刃是公认最经典的BB模具，退而求其次，3的模具也不错。人形很有层次感和曲线感。涂装较3有改进的地方，黑色部件的引入增强了色彩对比，比3的非灰即黄要好很多；最大的亮点是脸和触角的银柒涂装，3的灰脸看著像骷髅头，很恐怖。不过退步和进步一样明显，首先面具改成了V形描边，远不如之前的面部横描好看，现在一点都不想把面具拉下来了；此外，脚尖没有涂色也是个败笔。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ER428In6/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;头雕的细节刻画不错，还是BB一贯的嗪奶嘴的骷髅头，面具的涂装也很差，银柒涂装是唯一能挽回点儿颜面的地方。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ER428Z3G/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ER429Aqn/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;手臂采用非对称设计，右手手炮，左手是个半假手，只有大拇指可动，什么都握不住，只是个摆设，看看当年电影2的D级的战刃，完全不能比啊。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ER428D01/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;脚的设计很漂亮，不过虽然看起来支撑面很大，但由于踝关节不可左右摆动，导致接地性不好。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ER429gLn/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;所有BB模具都不能解决的大背包，现在似乎已经成为BB的特征了，好吧，即便接受这一点，这一整块棺材板好意思跟战刃的两级背板比么？&lt;/p&gt;
&lt;p&gt;关节的松紧度没有问题，可动性也不错，不过腰部不能转，头部只能左右转，不能抬头、低头。&lt;/p&gt;
&lt;p&gt;武器就是右手手炮，这货没有任何配件，如果说噱头的话，也就是手炮可以拉长和缩短，这点连D级玩具都不如啊。&lt;/p&gt;
&lt;p&gt;载具形态也不错，滚动性良好，可以摆出3的武装爆甲的形态，但是武装呢？！&lt;/p&gt;
&lt;p&gt;底部隐藏度一般，似乎电影系所有BB都有头无法隐藏的问题。&lt;/p&gt;
&lt;p&gt;最后放一张3的武装爆甲照，缅怀BB入宫前的峥嵘岁月。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ER44HJDK/medish.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>自驾白石山、满城汉墓（201507）</title><link>http://0x3f.org/posts/a-drive-to-baishi-mountain-and-a-kings-tomb-of-han/</link><pubDate>Wed, 29 Jul 2015 20:15:00 +0000</pubDate><guid>http://0x3f.org/posts/a-drive-to-baishi-mountain-and-a-kings-tomb-of-han/</guid><description>&lt;h2 id="行程"&gt;行程&lt;/h2&gt;
&lt;p&gt;D1：北京到白石山，爬山，到满城住宿。&lt;br&gt;
D2：看满城汉墓，回京。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaPbLj/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="d1-白石山"&gt;D1 白石山&lt;/h2&gt;
&lt;p&gt;原计划早上6点出发，该死的拖延症，收拾东西花了点时间，七点多才走。&lt;/p&gt;
&lt;p&gt;途径南六环、京石高速、廊涿高速、张石高速。易县以后进入山区，隧道又多又长，本着不超速、不随意变道、做中国好司机的原则，走得比较慢，十点多才到涞源。涞源出口很窄，堵了二十分钟。出高速到景区已经不远了，在东门停车场停好车。&lt;/p&gt;
&lt;p&gt;来前天气预报说有小雨，心说很好啊，我就喜欢下着小雨爬山，所以没带速干帽，结果是个闷热天儿，我去。&lt;/p&gt;
&lt;p&gt;十点四十，出发。我的艺名叫不逃票不舒服斯基，因为走正门太low了。不过逃票要早上四五点走野路，时间紧，任务重，还是low吧。头一天同程订的门票，比现买便宜十块，据说发表评价再退十块。坐摆渡车到祥云门，也可以坐索道。然后顺时针走环线。&lt;/p&gt;
&lt;p&gt;山里大部分路口都是局部路标，带张完整的路线图还是有必要的。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaP9T6/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我对所有以“传说”开头介绍的东西不感冒，总之这个塑像是环线的起点和终点。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaPQq7/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;一开始就走下坡，沿着峡壁的栈道下到飞狐峡，这一线主要是峡谷半山的栈道，是全环线最好的一段，我喜欢峡谷。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaQQZj/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;飞狐峡走的人少，多数时间太阳不直晒，风吹着，凉快。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaRttP/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我喜欢峡谷。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaRYSZ/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;每个山谷都应该有一条河，可惜。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaSCeW/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;逆风如解意，容易莫摧残。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaT6Td/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;仙人晒靴。不喜欢这种附会的东西。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaTCqU/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;太行之神。这货跟神有一毛钱关系么。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaULWh/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;好吧，这才是重点，玻璃栈道。一点儿都不吓银，而且很短，而且收费，看我的斯卡帕美不美。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaV9pl/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;回望走过的栈道，敢问路在何方。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaVIyf/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;过了玻璃栈道就是双雄石，好内涵的名字，剩下的路已经不多了，而且都是平路。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaW6zQ/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;猪八戒背媳妇儿。虽然附会，确实比较像，就是这媳妇儿砢碜了点儿。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaWrFX/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;走一圈环线用了4个小时。刚下山，到停车场，毫无征兆的一场暴雨，这酸爽，山里的天气真是孩子脸。&lt;/p&gt;
&lt;p&gt;驱车奔满城，走高速要绕很远，于是奔S332，看地图只有一百多公里。结果又干了三个多小时，天落黑才到酒店。&lt;/p&gt;
&lt;p&gt;刚开始的一段路还可以。小公路在太行山里蜿蜒，重山夹路，车少，路况也不错，偶尔掠过几个石筑的村落，甚至有牧人和羊群镶嵌在陡峭的青山上，恍如隔世。&lt;/p&gt;
&lt;p&gt;中间一段路况很差，再往下走，人烟逐渐增多，更多的是成群结队的重卡，很耽误时间，有时候走着走着停了，还以为前面堵车了，哪知道这孙子站路中间嘘嘘呢，知道燕赵民风骠悍，没想到这么骠悍。省道真练技术。&lt;/p&gt;
&lt;h2 id="d2-满城汉墓"&gt;D2 满城汉墓&lt;/h2&gt;
&lt;p&gt;我喜欢破破烂烂的地方，满城汉墓早在我的怨念单里。汉墓十墓九空，唯独这个是极少没被盗过的之一，光这个墓的陪葬，撑起了整个河北省博物馆。另外墓主人很有名，中山靖王，汉景帝庶子，汉武帝异母兄，刘备号称的祖宗。平生三大爱好，喝酒、吃肉、叮叮当当造小人儿。《史记》载其有子百二十人，按照正态分布，女儿也得有百二十人，刘营长辛苦。&lt;/p&gt;
&lt;p&gt;景区大门，我喜欢人少的地方。头一天在同程上订好的园区门票、窦绾墓、刘胜墓的联票，比现买便宜十块，一个景点分段收费，旅游业非常黑。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaXBGL/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;石像生和翁仲应该不是汉墓的原物。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaYlwl/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaZDpx/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;有索道，不过山不高，没必要。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZaZRzF/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;夫人窦绾墓在靖王墓北一百多米处，容积比靖王墓大，大概是靖王死在先，窦绾墓多施工了几年。&lt;/p&gt;
&lt;p&gt;墓门用砖砌墙，然后注入熔铁封死。倒这样的斗确实不容易。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb03TW/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;窦绾墓平面图。仿宫殿式布局，两个耳室一存车马，一存饮食。中室是客厅。侧室是带浴室的主卧。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb1g5N/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;墓道里非常凉快，和外面完全两个世界。两千年前的人，先用火灼烧石壁，再用水激，最后用铁器凿掉碎石，这样的工艺也算是巧夺天工了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb0yci/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb1xhm/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;南耳室是车库。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb1hLc/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;北耳室存放饮食。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb1D6u/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;中室灰常大。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb2wJB/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;渗水井和室内排水沟相连，组成很完善的排水系统。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb2QMD/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;金缕玉衣，仿品。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb2Xv0/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;侧室，窦绾的金缕玉衣和传说中的长信宫灯原本停放在这里。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EPZb4Cio/medish.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Swoole与PHP-FPM性能对比</title><link>http://0x3f.org/posts/swoole-vs-php-fpm/</link><pubDate>Tue, 14 Jul 2015 16:40:00 +0000</pubDate><guid>http://0x3f.org/posts/swoole-vs-php-fpm/</guid><description>&lt;p&gt;测试环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU: Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz&lt;/li&gt;
&lt;li&gt;MEM: 4G&lt;/li&gt;
&lt;li&gt;OS: Archlinux 64bit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;测试命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ab -c &lt;span class="m"&gt;200&lt;/span&gt; -n &lt;span class="m"&gt;200000&lt;/span&gt; -k http://127.0.0.1/test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="nginx--php-fpm"&gt;NGINX + PHP-FPM&lt;/h2&gt;
&lt;p&gt;Requests per second: 16240.50 [#/sec] (mean)&lt;br&gt;
Time per request: 12.315 [ms] (mean)&lt;/p&gt;
&lt;h2 id="nginx--swoole"&gt;NGINX + Swoole&lt;/h2&gt;
&lt;p&gt;Requests per second: 31284.57 [#/sec] (mean)&lt;br&gt;
Time per request: 6.393 [ms] (mean)&lt;/p&gt;
&lt;h2 id="swoole"&gt;Swoole&lt;/h2&gt;
&lt;p&gt;Requests per second: 99926.55 [#/sec] (mean)&lt;br&gt;
Time per request: 2.001 [ms] (mean)&lt;/p&gt;
&lt;h2 id="结论"&gt;结论&lt;/h2&gt;
&lt;p&gt;对一个最简单的PHP脚本做测试，排除业务逻辑的消耗的影响。Swoole威武。&lt;/p&gt;</description></item><item><title>变形金刚：KO电镀嘴炮OP</title><link>http://0x3f.org/posts/transformers-optimus-prime-ko-edition/</link><pubDate>Mon, 22 Jun 2015 20:35:00 +0000</pubDate><guid>http://0x3f.org/posts/transformers-optimus-prime-ko-edition/</guid><description>&lt;p&gt;嘴炮OP这个模具应该是电影系列十年来最好的模具，经典到一再复刻和改模，和原色双刀、DA28一起都属同模或改模版本。相比之下，这款模具在涂装上胜过同模其它版本，电镀件和银柒使人形、车形在色彩上对比鲜明，和银色飞翼搭配很自然。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EKm5Xn5y/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;人形正面比例协调，领袖级的大小更显霸气。腰部和小腿部的两对轮子太累赘，腰部的轮子完全可以设计成收纳到腰里。&lt;/p&gt;
&lt;p&gt;涂装上，除红蓝主色调外，其它位置主要填充银色金属柒，对比鲜明，很有质感。&lt;/p&gt;
&lt;p&gt;上下肢都采用齿轮关节，关节的松紧度方面表现很好。除了腰部不能转动，四肢和头部的转动辐度都很大。&lt;/p&gt;
&lt;p&gt;作为一款经典的L级模具，手居然是假手，很不可理解。&lt;/p&gt;
&lt;p&gt;踝关节可以左右摆动，所以脚的接地性没有问题，不过全身最大的两块电镀件居然踩在脚底板当鞋垫，真是无语了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EKmcV5LK/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这款模具之所以叫嘴炮OP，就是因为有嘴有炮。一般OP的模具的头雕都是带口罩的，而这款是露嘴的。其实我更喜欢带口罩的形象，机器人要嘴没什么用，尤其像大黄蜂那种嗪奶头的嘴，见一次吐一次。&lt;/p&gt;
&lt;p&gt;头雕很精细，细节的刻画和涂装都很到位，只是这长了鳃的OP是要配合天火马甲搞个海陆空三栖么。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EKmdnv02/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;背包不算大，不过还是过于突兀，尤其是这交叉的造型个人觉得很难看。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EKmd8JC8/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;炮是由两个油箱组合变形而成，虽然炮形比较奇葩，但是构思确实很新颖。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EKm4Xluq/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;受G1动画的影响，我觉得朴实无华的平头卡车更能显现OP的威严，电影版的狗头卡车多少有点浮夸。不过从还原电影的角度来说，这款模具的载具形态还是很不错的。尤其是两部分电镀件，遮光板和进气面板，非常闪亮。白色描边的火焰纹的刻画也很到位。&lt;/p&gt;
&lt;p&gt;由于车轮没有卡扣固定，并且有的车轮不能著地，所以载具形态的滚动性不好。&lt;/p&gt;
&lt;p&gt;L级模具的噱头一般是声光效果。这款模具有三个，一是人形状态下，扳下腹部机关，胸甲耸起的同时，胸部和眼睛会亮，OP喊：“I am Optimus Prime !”（&lt;strong&gt;其实不如喊那句最经典的：“Autobots, transform and roll out !”，向G1致敬会让很多人丧失抵抗力……&lt;/strong&gt;）；第二个是人形变车形时，上半身和下半身分离时，发出叽叽咔叽的变形音效；第三个是在车形状态下，扳动车头背部的开关，发出机枪扫射的声音。平心而论，这款模具的声光效果设计得还是不错的，人形、变形、车形三种状态都有照顾，不像变3的L级大黄蜂，所有声光效果都在那个巨大无比的鸡肋背包上。&lt;/p&gt;
&lt;p&gt;把玩性方面，由于体形较大，变形复杂度高，把玩起来流畅度并不高，不过这是L级模具的通病。&lt;/p&gt;
&lt;p&gt;此外，KO版的普遍问题都有，像左遮光板卡不紧、胸甲滑动不流畅。&lt;/p&gt;
&lt;p&gt;总之，这款KO双刀电镀嘴炮OP在模具、涂装、做工、用料等各方面的表现都不错，非神物而神物，压箱底还是可以胜任的。&lt;/p&gt;</description></item><item><title>PHP扩展框架的创建</title><link>http://0x3f.org/posts/create-php-extension-skeleton/</link><pubDate>Thu, 18 Jun 2015 14:15:00 +0000</pubDate><guid>http://0x3f.org/posts/create-php-extension-skeleton/</guid><description>&lt;h2 id="创建项目"&gt;创建项目&lt;/h2&gt;
&lt;p&gt;在PHP源码目录下的ext目录下执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ext_skel&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;extname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;foobar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;修改foobar/config.m4，移除以下三行前的dnl：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;dnl PHP_ARG_WITH(foobar, for foobar support,&lt;br&gt;
dnl Make sure that the comment is aligned:&lt;br&gt;
dnl [ &amp;ndash;with-foobar Include foobar support])&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="编译与安装"&gt;编译与安装&lt;/h2&gt;
&lt;p&gt;在foobar目录下执行以下命令，生成configure脚本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/bin/phpize
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;执行configure：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./configure --with-php-config&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/php-config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;编译安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;修改php.ini，启用扩展：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;extension&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;foobar.so&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>PHP流的上下文和过滤器的实现</title><link>http://0x3f.org/posts/contexts-and-filters-implementation-of-php/</link><pubDate>Mon, 15 Jun 2015 19:15:00 +0000</pubDate><guid>http://0x3f.org/posts/contexts-and-filters-implementation-of-php/</guid><description>&lt;h2 id="上下文的实现和应用"&gt;上下文的实现和应用&lt;/h2&gt;
&lt;p&gt;上下文包含流的选项和流的参数两部分内容。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;php_stream_context&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;php_stream_context_alloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;流的选项是一系列键值对。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;php_stream_context_set_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;php_stream_context&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;wrappername&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;optionname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;optionvalue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;php_stream_context_get_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;php_stream_context&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;wrappername&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;optionname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;***&lt;/span&gt;&lt;span class="n"&gt;optionvalue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;流的参数目前只实现对流的事件的回调，php_stream_context-&amp;gt;notifier存储如下结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="n"&gt;php_stream_notification_func&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dtor&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream_notifier&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;progress_max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;php_stream_notifier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;回调函数的原型为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="nf"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;php_stream_notification_func&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream_context&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;notifycode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;xmsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;xcode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;bytes_sofar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;bytes_max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;notifycode包含如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_RESOLVE：主机名解析完成&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_CONNECT：socket连接建立&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_AUTH_REQUIRED：需要验证&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_MIME_TYPE_IS：远程资源的MIME-Type可用&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_FILE_SIZE_IS：远程资源的大小可用&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_REDIRECTED：原始地址被跳转&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_PROGRESS：php_stream_notifier-&amp;gt;progress和progress_max（可能的）已更新&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_COMPLETED：流中已无可用数据&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_FAILURE：请求失败&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_AUTH_RESULT：远程验证已完成，并且可能是成功的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;severity包含如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_SEVERITY_INFO&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_SEVERITY_WARN&lt;/li&gt;
&lt;li&gt;PHP_STREAM_NOTIFY_SEVERITY_ERR&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;php_stream_notifier-&amp;gt;ptr用于存储附加数据，如果该数据需要手工回收，需指定php_stream_notifier-&amp;gt;dtor。&lt;/p&gt;
&lt;p&gt;php_stream_notifier-&amp;gt;mask如果被赋值severity，其它severity的事件将不会触发回调函数。&lt;/p&gt;
&lt;h2 id="过滤器的实现和应用"&gt;过滤器的实现和应用&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;span class="lnt"&gt;68
&lt;/span&gt;&lt;span class="lnt"&gt;69
&lt;/span&gt;&lt;span class="lnt"&gt;70
&lt;/span&gt;&lt;span class="lnt"&gt;71
&lt;/span&gt;&lt;span class="lnt"&gt;72
&lt;/span&gt;&lt;span class="lnt"&gt;73
&lt;/span&gt;&lt;span class="lnt"&gt;74
&lt;/span&gt;&lt;span class="lnt"&gt;75
&lt;/span&gt;&lt;span class="lnt"&gt;76
&lt;/span&gt;&lt;span class="lnt"&gt;77
&lt;/span&gt;&lt;span class="lnt"&gt;78
&lt;/span&gt;&lt;span class="lnt"&gt;79
&lt;/span&gt;&lt;span class="lnt"&gt;80
&lt;/span&gt;&lt;span class="lnt"&gt;81
&lt;/span&gt;&lt;span class="lnt"&gt;82
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;#34;ext/standard/php_string.h&amp;#34;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;is_persistent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;from_chars&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;to_chars&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tr_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;php_donie_filter_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;php_stream_filter_status_t&lt;/span&gt; &lt;span class="nf"&gt;php_donie_stream_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;php_stream_filter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;thisfilter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_bucket_brigade&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buckets_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_bucket_brigade&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buckets_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bytes_consumed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_donie_filter_data&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thisfilter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;abstract&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;consumed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets_in&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;php_stream_bucket_make_writeable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets_in&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_strtr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buflen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;from_chars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;to_chars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tr_len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;consumed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buflen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_stream_bucket_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes_consumed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bytes_consumed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PSFS_PASS_ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;php_donie_stream_filter_dtor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_filter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;thisfilter&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_donie_filter_data&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thisfilter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;abstract&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;pefree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;is_persistent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;php_stream_filter_ops&lt;/span&gt; &lt;span class="n"&gt;php_donie_stream_filter_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_donie_stream_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_donie_stream_filter_dtor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;donie.to_upper_case&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;php_stream_filter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;php_donie_stream_filter_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;persistent&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_donie_filter_data&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pemalloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;php_donie_filter_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;persistent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;is_persistent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;persistent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;from_chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;abcdefghijklmnopqrstuvwxyz&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;to_chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ABCDEFGHIJKLMNOPQRSTUVWXYZ&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tr_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;from_chars&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;php_stream_filter_alloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;php_donie_stream_filter_ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;persistent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;php_stream_filter_factory&lt;/span&gt; &lt;span class="n"&gt;php_donie_stream_uppercase_factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_donie_stream_filter_create&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_MINIT_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* register a filter */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_stream_filter_register_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;donie.to_upper_case&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;php_donie_stream_uppercase_factory&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_MSHUTDOWN_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* unregister the filter */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_stream_filter_unregister_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;donie.to_upper_case&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="注册和注销"&gt;注册和注销&lt;/h3&gt;
&lt;p&gt;分别在MINIT和MSHUTDOWN函数中调用php_stream_filter_register_factory()和php_stream_filter_unregister_factory()注册和注销过滤器。&lt;/p&gt;</description></item><item><title>使用gn操作增强Vim的搜索</title><link>http://0x3f.org/posts/enhance-search-with-gn-in-vim/</link><pubDate>Sun, 14 Jun 2015 21:16:00 +0000</pubDate><guid>http://0x3f.org/posts/enhance-search-with-gn-in-vim/</guid><description>&lt;p&gt;gn是Vim 7.4新增的一个操作（motion），作用是跳到并选中下一个搜索匹配项。&lt;/p&gt;
&lt;p&gt;具体说，Vim里执行搜索后，执行n操作只会跳转到下一个匹配项，而不选中它。但是我们往往需要对匹配项执行一些修改操作，例如替换、删除或修改大小写等，如果先跳转再执行对应操作，会比较繁琐。gn可以和相应的操作结合，简化这些过程。&lt;/p&gt;
&lt;p&gt;举个栗子。如果要把所有的win、linux替换成大写，可以先用正则搜索“&lt;strong&gt;\(win|linux\)\C&lt;/strong&gt;”，然后执行“&lt;strong&gt;gUgn&lt;/strong&gt;”，此时下一个匹配的结果就会被替换成大写，然后直接执行“&lt;strong&gt;.&lt;/strong&gt;”重复上次操作即可。&lt;/p&gt;
&lt;p&gt;此外，常用的组合有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cgn: 删除下一个匹配项，并进入插入模式。&lt;/li&gt;
&lt;li&gt;dgn: 删除下一个匹配项，并保持常规模式。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;和操作“&lt;strong&gt;N&lt;/strong&gt;”相同，执行“&lt;strong&gt;gN&lt;/strong&gt;”是逆向操作。&lt;/p&gt;</description></item><item><title>在i3wm状态栏显示股票信息</title><link>http://0x3f.org/posts/show-stocks-in-i3status/</link><pubDate>Fri, 12 Jun 2015 17:39:00 +0000</pubDate><guid>http://0x3f.org/posts/show-stocks-in-i3status/</guid><description>&lt;p&gt;效果如图：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EIOXvoh8/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;创建脚本，并赋可执行权限：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# shell script to prepend i3status with more stuff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;STOCK_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;realpath &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;xargs dirname&lt;span class="sb"&gt;`&lt;/span&gt;/stock.php
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;i3status &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; :
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;stock_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; -x &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$STOCK_SCRIPT&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;stock_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nv"&gt;$STOCK_SCRIPT&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;read&lt;/span&gt; line
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# if output_format = i3bar in i3status.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;stock_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;[{ \&amp;#34;full_text\&amp;#34;: \&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;stock_info&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34; },&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="p"&gt;/[/&lt;/span&gt;&lt;span class="nv"&gt;$stock_info&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# # if not output_format = i3bar in i3status.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# echo &amp;#34;$stock_info | $line&amp;#34; || exit 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果i3status.conf中启用了JSON格式输出（支持颜色），应启用上面脚本中第一块的代码，否则使用后面的。启动JSON格式输出的内容具体如下：&lt;/p&gt;</description></item><item><title>PHP流的操作</title><link>http://0x3f.org/posts/stream-operations-of-php/</link><pubDate>Mon, 01 Jun 2015 15:33:00 +0000</pubDate><guid>http://0x3f.org/posts/stream-operations-of-php/</guid><description>&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* reimplement fopen using stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;ZEND_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie_stream_fopen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;path_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ENFORCE_SAFE_MODE&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;REPORT_ERRORS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ZEND_NUM_ARGS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ss&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;path_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mode_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;php_stream_open_wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RETURN_FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_stream_to_zval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;php_stream_open_wrapper()是对文件类型资源创建流的方法，此外还有基于socket的流、目录流和特殊流三种。php_stream_to_zval()用于把流实例转换成zval结构。&lt;/p&gt;
&lt;h2 id="创建文件类型的流"&gt;创建文件类型的流&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define php_stream_open_wrapper_ex(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC TSRMLS_CC)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;参数path是文件名或URL，mode是模式字符串，options是选项组合。php_stream_open_wrapper_ex()允许指定一个流的上下文。&lt;/p&gt;</description></item><item><title>变形金刚：祖国合金放大版探长</title><link>http://0x3f.org/posts/hound-of-transformers-4/</link><pubDate>Sun, 31 May 2015 17:39:00 +0000</pubDate><guid>http://0x3f.org/posts/hound-of-transformers-4/</guid><description>&lt;p&gt;探长可以和平头OP并列变四最好的模具，人形和车形俱佳。但是官版的V级神物实在鸡肋，所以祖国版准L级模具实在是拯救巨大控的好物。除了放大，探长的整个车头都是合金件，既有质感又有份量。涂装较官版也有改进，胸甲和轮轱上了银柒，枪管上了金柒，车形后部增加了火焰纹，不像官版那么素。最重要的是祖国版的做工很好，关节松紧适度，车形闭合得很好。&lt;/p&gt;
&lt;p&gt;祖国版的探长目前有三个版本，普通版、叼烟版和蓝色版。普通版和官版是一致的。叼烟版的头雕是叼著烟的。蓝色版的外形和普通版一样，但是涂成了深蓝色，而且附送两个塑料小人。我最喜欢的叼烟版，不知道帝都禁烟后还能不能买到……&lt;/p&gt;
&lt;p&gt;虽然祖国版整体而言是很好的东东，不过厂家的品控做得很不好，我玩儿过几个实体才挑到合适的，有的车头背部塑料板开盒就是烂的，有的轮轱个别没有涂银柒，比较普遍的现象是大枪插不进背部凹槽，还有个别关节比较松。所以买祖国版还是蛮拼人品的。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EGZsq1TR/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;人形体格匀称，没有背包，除了门板手外，没有累赘部件，虽然门板可以卸掉，但并没有地方收纳。&lt;/p&gt;
&lt;p&gt;头雕精细度一般，不过雪茄的加入是个大大的加分项。&lt;/p&gt;
&lt;p&gt;涂装方面，用军绿色作为基色，银灰搭配，很不错。&lt;/p&gt;
&lt;p&gt;虽然没有用到齿轮关节，不过松紧度都很好。腿部向前可以平抬，不能后踢。由于膝关节较高，做不了跪姿。腰部可以360度旋转。手臂大风车没有问题。头部可以左右转动很小的角度，不能抬头、低头。&lt;/p&gt;
&lt;p&gt;前脚掌可以左右摆动，提供了一定的接地性。&lt;/p&gt;
&lt;p&gt;一般比较用心的模具都会在可玩性上加一个噱头，比如平头OP的枪是可以发射子弹的。探长的噱头就是组合武器，拼装后的大枪还是很霸气的，只是一只手举不起来，必须双手托枪。武器的收纳方面做得很好，无论是人形还是载具形态，都可以完美收纳所有武器。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EGZrLORA/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;拆开挂满身，不愧是个武器库。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EGZrLe2y/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;车形的原型是奥什科什防务军用战术装甲车，也非常帅。有两个轮子不能著地，不过整体滚动性不错。&lt;/p&gt;
&lt;p&gt;武器的偷胶有点过头，胯部的两把枪和大枪都有很大程度的偷胶，这是个很大的扣分项。&lt;/p&gt;
&lt;p&gt;玩具变形流畅，把玩性的表现非常好。&lt;/p&gt;</description></item><item><title>PHP流的实现</title><link>http://0x3f.org/posts/stream-implementation-in-php/</link><pubDate>Fri, 29 May 2015 17:33:00 +0000</pubDate><guid>http://0x3f.org/posts/stream-implementation-in-php/</guid><description>&lt;h2 id="流的概念"&gt;流的概念&lt;/h2&gt;
&lt;p&gt;流是一系列概念的集合，包括流包装器、流资源、流操作、上下文等内容。流是对不同资源进行操作的抽象，允许线性地从指定位置读取或写入数据，通过一套统一的API简化对资源操作的实现。&lt;/p&gt;
&lt;p&gt;流由scheme://target指代，scheme是包装器（Wrapper）的名字，target是流的目标地址。&lt;/p&gt;
&lt;p&gt;PHP的流的实现较Java简单，后者可以通过嵌套实现更灵活的应用。&lt;/p&gt;
&lt;h2 id="流的实现"&gt;流的实现&lt;/h2&gt;
&lt;h3 id="存储结构"&gt;存储结构&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_php_stream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_ops&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;abstract&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* convenience pointer for abstraction */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_filter_chain&lt;/span&gt; &lt;span class="n"&gt;readfilters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writefilters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_wrapper&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* which wrapper was used to open the stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;wrapperthis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* convenience pointer for a instance of a wrapper */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;wrapperdata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* fgetwrapperdata retrieves this */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fgetss_state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* for fgetss to handle multiline tags */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;is_persistent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="cm"&gt;/* &amp;#34;rwb&amp;#34; etc. ala stdio */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rsrc_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* used for auto-cleanup */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;in_free&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* to prevent recursion during free */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* so we know how to clean it up correctly. This should be set to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * PHP_STREAM_FCLOSE_XXX as appropriate */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fclose_stdiocast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stdiocast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* cache this, otherwise we might leak! */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#if ZEND_DEBUG
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__exposed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* non-zero if exposed as a zval somewhere */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;orig_path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_stream_context&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* PHP_STREAM_FLAG_XXX */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* buffer */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* of underlying stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;readbuf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;readbuflen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;readpos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;writepos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* how much data to read when filling buffer */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#if ZEND_DEBUG
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;open_filename&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;open_lineno&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;enclosing_stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* this is a private stream owned by enclosing_stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="cm"&gt;/* php_stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_php_stream_ops&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* stdio like functions - these are mandatory! */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;close_handle&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* label for this ops structure */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* these are optional */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;seek&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;whence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;newoffset&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;castas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;php_stream_statbuf&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ssb&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;set_option&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;php_stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptrparam&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_DC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;php_stream_ops&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;php_stream结构体最重要的成员是ops和abstract。ops包含了流实例的所有操作逻辑，特别地，php_stream_ops-&amp;gt;close在php_stream结构被回收前提供了回收与该流实例相关的资源的机会。abstract用来存储一个自定义结构的数据，在流的操作逻辑里可以方便的访问。&lt;/p&gt;</description></item><item><title>在Archlinux ARM上使用DS18B20温度传感器</title><link>http://0x3f.org/posts/setup-ds18b20-on-archlinux/</link><pubDate>Mon, 25 May 2015 15:30:00 +0000</pubDate><guid>http://0x3f.org/posts/setup-ds18b20-on-archlinux/</guid><description>&lt;p&gt;线路图：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EG46yU99/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;修改/boot/config.txt，启用w1内核模块。配置文件中有两部分关于w1的内容，一个只使用一个GPIO引脚，需要自行添加上拉电阻，另一个使用一个额外的GPIO引脚作上拉。&lt;/p&gt;
&lt;p&gt;使用Python模块w1thermsensor读数，用法见&lt;a href="https://github.com/timofurrer/w1thermsensor"&gt;这里&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>变形金刚：原大祖国合金版平头OP</title><link>http://0x3f.org/posts/transformers-optimus-prime/</link><pubDate>Sat, 09 May 2015 21:26:00 +0000</pubDate><guid>http://0x3f.org/posts/transformers-optimus-prime/</guid><description>&lt;p&gt;一开始我不太喜欢电影版变形金刚，因为太像人就缺少科技感，我至今都认为G1是不可逾越的经典。不过变4的这款V级平头OP确实是个经典的模具，一个好的变形金刚玩具应有标准几乎都符合。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EDFWGrQR/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;人形身材匀称、没有冗余部件，关键是无背包，很少有能做到这一点的模具，几乎所有大黄蜂最大的败笔都是有个巨大的背包。涂装鲜艳、视觉效果强烈，作为一个Prime，搞得满身火焰纹、花里胡哨的真的好么？&lt;/p&gt;
&lt;p&gt;关节的松紧度方面，四肢主关节采用齿轮关节，表现不错，不过肘关节是圆形关节，转动次数多了不知道会不会松。&lt;/p&gt;
&lt;p&gt;由于人形没有太多的累赘，所以可动性方面没有问题，腰部也是可以360度旋转的。&lt;/p&gt;
&lt;p&gt;手脚方面，一个V级的玩具，用假手也就不说什么了。不过由于踝关节不能左右摆动，所以脚的接地性不好。&lt;/p&gt;
&lt;p&gt;头雕不够精细，眼睛是可以透光的。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EDFU2oxD/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;车形也是个亮点。我一直不喜欢电影版里那种狗头车，太张扬，反而G1里那种平头车更显内敛，才有大哥气质。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EDFU1X5C/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;做工和用料很不错。我不是孩控，做工和价格都很重要，祖国版用料很扎实，而且有合金部件，做工也不弱于孩版，再加上这白菜价，孩版就呵呵哒了。&lt;/p&gt;
&lt;p&gt;滚动性不好，有的车轮不能著地，而且部分车轮本身转动不畅。&lt;/p&gt;
&lt;p&gt;枪是可以发射子弹的，可玩性有加分。另买的审判之剑真的很帅，否则堂堂Prime单持一把大手枪显得太素了。&lt;/p&gt;
&lt;p&gt;变形的复杂度恰到好处，只是手臂收纳到车头时很紧，流畅度上有扣分。&lt;/p&gt;
&lt;p&gt;这是款很经典的模具，很期待放大的祖国合金版。&lt;/p&gt;</description></item><item><title>PHP全局变量的实现和操作</title><link>http://0x3f.org/posts/globals-implementation-in-php/</link><pubDate>Fri, 08 May 2015 17:23:00 +0000</pubDate><guid>http://0x3f.org/posts/globals-implementation-in-php/</guid><description>&lt;h2 id="扩展内部的全局变量"&gt;扩展内部的全局变量&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;ZEND_BEGIN_MODULE_GLOBALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;global_long&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;global_string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;ZEND_END_MODULE_GLOBALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;ZEND_DECLARE_MODULE_GLOBALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;php_donie_init_globals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zend_donie_globals&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;donie_globals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;donie_globals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;global_long&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2015&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;donie_globals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;global_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Long live Donie Leigh !&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;php_donie_globals_dtor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zend_donie_globals&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;donie_globals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;php_donie_globals_dtor triggered.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_MINIT_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* init extension globals */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ZEND_INIT_MODULE_GLOBALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;php_donie_init_globals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;php_donie_globals_dtor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_RSHUTDOWN_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#ifndef ZTS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_donie_globals_dtor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;donie_globals&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;ZEND_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie_test_ext_globals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;DONIE_G&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;global_string&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="声明"&gt;声明&lt;/h3&gt;
&lt;p&gt;ZEND_BEGIN_MODULE_GLOBALS和ZEND_END_MODULE_GLOBALS及其间的内容实际上声明了一个结构体zend_donie_globals。&lt;/p&gt;</description></item><item><title>PHP常量的实现和操作</title><link>http://0x3f.org/posts/constant-implementation-in-php/</link><pubDate>Thu, 07 May 2015 16:29:00 +0000</pubDate><guid>http://0x3f.org/posts/constant-implementation-in-php/</guid><description>&lt;h2 id="存储结构"&gt;存储结构&lt;/h2&gt;
&lt;p&gt;常量存储在哈希表EG(zend_constants)中。&lt;/p&gt;
&lt;p&gt;常量的结构定义为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_zend_constant&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;name_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;module_number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;zend_constant&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;value是常量的值，是一个zval。name是常量名。module_number是模块被加载时，PHP内核在MINIT和RINIT方法的原型里默认传递的一个值，作为模块清理时的线索，在注册常量的接口里直接传递即可。&lt;/p&gt;
&lt;p&gt;flags是常量的标识或标识组合：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CONST_CS&lt;/li&gt;
&lt;li&gt;CONST_PERSISTENT&lt;/li&gt;
&lt;li&gt;CONST_CT_SUBST&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CONST_CS表示常量名对大小写敏感，对应PHP函数define()的第三个参数，TRUE、FALSE、NULL这些常量名对大小写是不敏感的。CONST_PERSISTENT表示常量在请求结束后被保存，只在PHP进程结束时才销毁，一般在MINIT中定义的常量应该指定此参数，RINIT中定义的不指定。CONST_CT_SUBST表示在编译时可替换，TRUE、FALSE、NULL、ZEND_THREAD_SAFE、ZEND_DEBUG_BUILD属于此类。&lt;/p&gt;
&lt;h2 id="常量的声明"&gt;常量的声明&lt;/h2&gt;
&lt;p&gt;常量的声明方法有两种，简单的使用宏函数族REGISTER_*_CONSTANT()：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;REGISTER_NULL_CONSTANT(name, flags)
REGISTER_BOOL_CONSTANT(name, bval, flags)
REGISTER_LONG_CONSTANT(name, lval, flags)
REGISTER_DOUBLE_CONSTANT(name, dval, flags)
REGISTER_STRING_CONSTANT(name, str, flags)
REGISTER_STRINGL_CONSTANT(name, str, len, flags)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于不需指定常量名长度，所以name参数应直接使用字符串，而不是char*。&lt;/p&gt;
&lt;p&gt;如需使用变量作为name参数，使用zend_register_*_constant()函数族，并指定变量名长度（sizeof(name)）。上面的宏函数其实是对这族函数的封装。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;void zend_register_long_constant(char *name, uint name_len, long lval, int flags, int module_number TSRMLS_DC)
void zend_register_double_constant(char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC)
void zend_register_bool_constant(const char *name, uint name_len, zend_bool bval, int flags, int module_number TSRMLS_DC)
void zend_register_string_constant(char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC)
void zend_register_stringl_constant(char *name, uint name_len, char *strval, uint strlen, int flags, int module_number TSRMLS_DC)&lt;/p&gt;</description></item><item><title>PHP资源的实现和操作</title><link>http://0x3f.org/posts/resource-implementation-in-php/</link><pubDate>Tue, 05 May 2015 18:53:00 +0000</pubDate><guid>http://0x3f.org/posts/resource-implementation-in-php/</guid><description>&lt;h2 id="存储结构"&gt;存储结构&lt;/h2&gt;
&lt;p&gt;资源变量也是一个zval结构，zval-&amp;gt;type == IS_RESOURCE，zval-&amp;gt;value-&amp;gt;lval存储一个整数，此整数为资源数据在存储资源的哈希表中的索引。&lt;/p&gt;
&lt;p&gt;资源数据的结构为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_zend_rsrc_list_entry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;refcount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;zend_rsrc_list_entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="常规资源与持久资源"&gt;常规资源与持久资源&lt;/h3&gt;
&lt;p&gt;有两个存储资源数据的哈希表。EG(regular_list)存储常规资源，EG(persistent_list)存储持久资源。&lt;/p&gt;
&lt;p&gt;常规资源对应的变量在作用域结束后会被内核回收，对应的资源数据也会被销毁。持久资源可以保持并被多次请求使用。持久资源的自动析构发生在PHP进程退出时。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;重新实现基本的文件句柄和相关操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt; 10
&lt;/span&gt;&lt;span class="lnt"&gt; 11
&lt;/span&gt;&lt;span class="lnt"&gt; 12
&lt;/span&gt;&lt;span class="lnt"&gt; 13
&lt;/span&gt;&lt;span class="lnt"&gt; 14
&lt;/span&gt;&lt;span class="lnt"&gt; 15
&lt;/span&gt;&lt;span class="lnt"&gt; 16
&lt;/span&gt;&lt;span class="lnt"&gt; 17
&lt;/span&gt;&lt;span class="lnt"&gt; 18
&lt;/span&gt;&lt;span class="lnt"&gt; 19
&lt;/span&gt;&lt;span class="lnt"&gt; 20
&lt;/span&gt;&lt;span class="lnt"&gt; 21
&lt;/span&gt;&lt;span class="lnt"&gt; 22
&lt;/span&gt;&lt;span class="lnt"&gt; 23
&lt;/span&gt;&lt;span class="lnt"&gt; 24
&lt;/span&gt;&lt;span class="lnt"&gt; 25
&lt;/span&gt;&lt;span class="lnt"&gt; 26
&lt;/span&gt;&lt;span class="lnt"&gt; 27
&lt;/span&gt;&lt;span class="lnt"&gt; 28
&lt;/span&gt;&lt;span class="lnt"&gt; 29
&lt;/span&gt;&lt;span class="lnt"&gt; 30
&lt;/span&gt;&lt;span class="lnt"&gt; 31
&lt;/span&gt;&lt;span class="lnt"&gt; 32
&lt;/span&gt;&lt;span class="lnt"&gt; 33
&lt;/span&gt;&lt;span class="lnt"&gt; 34
&lt;/span&gt;&lt;span class="lnt"&gt; 35
&lt;/span&gt;&lt;span class="lnt"&gt; 36
&lt;/span&gt;&lt;span class="lnt"&gt; 37
&lt;/span&gt;&lt;span class="lnt"&gt; 38
&lt;/span&gt;&lt;span class="lnt"&gt; 39
&lt;/span&gt;&lt;span class="lnt"&gt; 40
&lt;/span&gt;&lt;span class="lnt"&gt; 41
&lt;/span&gt;&lt;span class="lnt"&gt; 42
&lt;/span&gt;&lt;span class="lnt"&gt; 43
&lt;/span&gt;&lt;span class="lnt"&gt; 44
&lt;/span&gt;&lt;span class="lnt"&gt; 45
&lt;/span&gt;&lt;span class="lnt"&gt; 46
&lt;/span&gt;&lt;span class="lnt"&gt; 47
&lt;/span&gt;&lt;span class="lnt"&gt; 48
&lt;/span&gt;&lt;span class="lnt"&gt; 49
&lt;/span&gt;&lt;span class="lnt"&gt; 50
&lt;/span&gt;&lt;span class="lnt"&gt; 51
&lt;/span&gt;&lt;span class="lnt"&gt; 52
&lt;/span&gt;&lt;span class="lnt"&gt; 53
&lt;/span&gt;&lt;span class="lnt"&gt; 54
&lt;/span&gt;&lt;span class="lnt"&gt; 55
&lt;/span&gt;&lt;span class="lnt"&gt; 56
&lt;/span&gt;&lt;span class="lnt"&gt; 57
&lt;/span&gt;&lt;span class="lnt"&gt; 58
&lt;/span&gt;&lt;span class="lnt"&gt; 59
&lt;/span&gt;&lt;span class="lnt"&gt; 60
&lt;/span&gt;&lt;span class="lnt"&gt; 61
&lt;/span&gt;&lt;span class="lnt"&gt; 62
&lt;/span&gt;&lt;span class="lnt"&gt; 63
&lt;/span&gt;&lt;span class="lnt"&gt; 64
&lt;/span&gt;&lt;span class="lnt"&gt; 65
&lt;/span&gt;&lt;span class="lnt"&gt; 66
&lt;/span&gt;&lt;span class="lnt"&gt; 67
&lt;/span&gt;&lt;span class="lnt"&gt; 68
&lt;/span&gt;&lt;span class="lnt"&gt; 69
&lt;/span&gt;&lt;span class="lnt"&gt; 70
&lt;/span&gt;&lt;span class="lnt"&gt; 71
&lt;/span&gt;&lt;span class="lnt"&gt; 72
&lt;/span&gt;&lt;span class="lnt"&gt; 73
&lt;/span&gt;&lt;span class="lnt"&gt; 74
&lt;/span&gt;&lt;span class="lnt"&gt; 75
&lt;/span&gt;&lt;span class="lnt"&gt; 76
&lt;/span&gt;&lt;span class="lnt"&gt; 77
&lt;/span&gt;&lt;span class="lnt"&gt; 78
&lt;/span&gt;&lt;span class="lnt"&gt; 79
&lt;/span&gt;&lt;span class="lnt"&gt; 80
&lt;/span&gt;&lt;span class="lnt"&gt; 81
&lt;/span&gt;&lt;span class="lnt"&gt; 82
&lt;/span&gt;&lt;span class="lnt"&gt; 83
&lt;/span&gt;&lt;span class="lnt"&gt; 84
&lt;/span&gt;&lt;span class="lnt"&gt; 85
&lt;/span&gt;&lt;span class="lnt"&gt; 86
&lt;/span&gt;&lt;span class="lnt"&gt; 87
&lt;/span&gt;&lt;span class="lnt"&gt; 88
&lt;/span&gt;&lt;span class="lnt"&gt; 89
&lt;/span&gt;&lt;span class="lnt"&gt; 90
&lt;/span&gt;&lt;span class="lnt"&gt; 91
&lt;/span&gt;&lt;span class="lnt"&gt; 92
&lt;/span&gt;&lt;span class="lnt"&gt; 93
&lt;/span&gt;&lt;span class="lnt"&gt; 94
&lt;/span&gt;&lt;span class="lnt"&gt; 95
&lt;/span&gt;&lt;span class="lnt"&gt; 96
&lt;/span&gt;&lt;span class="lnt"&gt; 97
&lt;/span&gt;&lt;span class="lnt"&gt; 98
&lt;/span&gt;&lt;span class="lnt"&gt; 99
&lt;/span&gt;&lt;span class="lnt"&gt;100
&lt;/span&gt;&lt;span class="lnt"&gt;101
&lt;/span&gt;&lt;span class="lnt"&gt;102
&lt;/span&gt;&lt;span class="lnt"&gt;103
&lt;/span&gt;&lt;span class="lnt"&gt;104
&lt;/span&gt;&lt;span class="lnt"&gt;105
&lt;/span&gt;&lt;span class="lnt"&gt;106
&lt;/span&gt;&lt;span class="lnt"&gt;107
&lt;/span&gt;&lt;span class="lnt"&gt;108
&lt;/span&gt;&lt;span class="lnt"&gt;109
&lt;/span&gt;&lt;span class="lnt"&gt;110
&lt;/span&gt;&lt;span class="lnt"&gt;111
&lt;/span&gt;&lt;span class="lnt"&gt;112
&lt;/span&gt;&lt;span class="lnt"&gt;113
&lt;/span&gt;&lt;span class="lnt"&gt;114
&lt;/span&gt;&lt;span class="lnt"&gt;115
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 资源名称
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define PHP_DONIE_RES_NAME_FILE &amp;#34;Donie&amp;#39;s File Descriptor&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 资源类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor_persist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 资源析构函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;php_donie_file_descriptor_dtor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zend_rsrc_list_entry&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rsrc&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;rsrc&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 在扩展的MINIT方法里创建资源类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_MINIT_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* create a new resource type */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;le_donie_file_descriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zend_register_list_destructors_ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;php_donie_file_descriptor_dtor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PHP_DONIE_RES_NAME_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;module_number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* create a persistent resource type */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;le_donie_file_descriptor_persist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zend_register_list_destructors_ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;php_donie_file_descriptor_dtor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PHP_DONIE_RES_NAME_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;module_number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 文件打开操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie_fopen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;filename_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_bool&lt;/span&gt; &lt;span class="n"&gt;persist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;hash_key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash_key_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;list_entry&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;persist_file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ZEND_NUM_ARGS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ss|b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;filename_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mode_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;RETURN_NULL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;filename_len&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mode_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_error_docref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;E_WARNING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Invalid file name or mode.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RETURN_FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* reuse persistent resource if exists */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hash_key_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hash_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;php_donie_file_descriptor:%s-%s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_hash_find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;EG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persistent_list&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;hash_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hash_key_len&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;persist_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ZEND_REGISTER_RESOURCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;persist_file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor_persist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;efree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_error_docref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;E_WARNING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Failed opening %s with mode %s.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RETURN_FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* this is the key point for registering resources */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ZEND_REGISTER_RESOURCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor_persist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;list_entry&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor_persist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;zend_hash_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;EG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persistent_list&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;hash_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hash_key_len&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list_entry&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ZEND_REGISTER_RESOURCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;efree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 文件写操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie_fwrite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file_resource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;data_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ZEND_NUM_ARGS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;rs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;file_resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;data_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;RETURN_NULL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ZEND_FETCH_RESOURCE2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;file_resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PHP_DONIE_RES_NAME_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor_persist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;RETURN_LONG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 文件关闭操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie_fclose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file_resource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ZEND_NUM_ARGS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;file_resource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;RETURN_NULL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ZEND_FETCH_RESOURCE2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;file_resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PHP_DONIE_RES_NAME_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le_donie_file_descriptor_persist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;zend_hash_index_del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;EG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regular_list&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Z_RESVAL_P&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_resource&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RETURN_TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="创建新资源类型"&gt;创建新资源类型&lt;/h3&gt;
&lt;p&gt;zend_register_list_destructors_ex()创建新资源类型，并注册该资源类型的析构函数、资源名称。第一个参数是常规资源的析构函数，第二个是持久资源的析构函数，此处创建的是常规资源类型，故第二个参数不指定。&lt;/p&gt;</description></item><item><title>PHP对象的实现和操作</title><link>http://0x3f.org/posts/object-implementation-in-php/</link><pubDate>Wed, 29 Apr 2015 23:00:00 +0000</pubDate><guid>http://0x3f.org/posts/object-implementation-in-php/</guid><description>&lt;h2 id="object的存储结构"&gt;Object的存储结构&lt;/h2&gt;
&lt;p&gt;对象实例用zval存储。zval-&amp;gt;type == IS_OBJECT，zval-&amp;gt;value-&amp;gt;obj存储zend_object_value类型的结构体变量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_zend_object_value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_object_handle&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;zend_object_handlers&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;zend_object_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;zend_object_handle是一个unsigned int，是对象的ID。zend_object_handlers存储对象所有的行为。&lt;/p&gt;
&lt;h2 id="object的实例化过程"&gt;Object的实例化过程&lt;/h2&gt;
&lt;p&gt;Object的初始化用以下几个宏函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;object_init(zval *arg)&lt;/li&gt;
&lt;li&gt;object_init_ex(zval *arg, zend_class_entry *class_type)&lt;/li&gt;
&lt;li&gt;object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;底层都是调用_object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties)实现。这个函数做以下几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查类是否可实例化（例如接口、抽象类等不允许初始化）&lt;/li&gt;
&lt;li&gt;处理类常量&lt;/li&gt;
&lt;li&gt;检查类是否存在自定义实例化逻辑
&lt;ul&gt;
&lt;li&gt;若存在，调用自定义实例化逻辑&lt;/li&gt;
&lt;li&gt;若不存在，调用缺省的函数zend_objects_new(zend_object **object, zend_class_entry *class_type)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;把实例化的zend_object类型的数据存入zval中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;zend_objects_new()做这些事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分配一个zend_object类型的内存空间&lt;/li&gt;
&lt;li&gt;初始化zend_object类型数据&lt;/li&gt;
&lt;li&gt;把zend_object类型数据存入对象仓库（Objects Store）
&lt;ul&gt;
&lt;li&gt;zend_objects_store_put(void *object, zend_objects_store_dtor_t dtor, zend_objects_free_object_storage_t free_storage, zend_objects_store_clone_t clone）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="zend_object的存储结构"&gt;zend_object的存储结构&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_zend_object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_class_entry&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ce&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HashTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;properties_table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HashTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;guards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* protects from __get/__set ... recursion */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;zend_object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;ce是类的定义。properties_table存储类里预定义的属性。properties存储非预定义属性。&lt;/p&gt;</description></item><item><title>PHP类和接口的实现</title><link>http://0x3f.org/posts/class-interface-implementation-in-php/</link><pubDate>Tue, 28 Apr 2015 18:38:00 +0000</pubDate><guid>http://0x3f.org/posts/class-interface-implementation-in-php/</guid><description>&lt;h2 id="class的实现"&gt;Class的实现&lt;/h2&gt;
&lt;p&gt;类的注册是在扩展的MINIT方法里。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt; 10
&lt;/span&gt;&lt;span class="lnt"&gt; 11
&lt;/span&gt;&lt;span class="lnt"&gt; 12
&lt;/span&gt;&lt;span class="lnt"&gt; 13
&lt;/span&gt;&lt;span class="lnt"&gt; 14
&lt;/span&gt;&lt;span class="lnt"&gt; 15
&lt;/span&gt;&lt;span class="lnt"&gt; 16
&lt;/span&gt;&lt;span class="lnt"&gt; 17
&lt;/span&gt;&lt;span class="lnt"&gt; 18
&lt;/span&gt;&lt;span class="lnt"&gt; 19
&lt;/span&gt;&lt;span class="lnt"&gt; 20
&lt;/span&gt;&lt;span class="lnt"&gt; 21
&lt;/span&gt;&lt;span class="lnt"&gt; 22
&lt;/span&gt;&lt;span class="lnt"&gt; 23
&lt;/span&gt;&lt;span class="lnt"&gt; 24
&lt;/span&gt;&lt;span class="lnt"&gt; 25
&lt;/span&gt;&lt;span class="lnt"&gt; 26
&lt;/span&gt;&lt;span class="lnt"&gt; 27
&lt;/span&gt;&lt;span class="lnt"&gt; 28
&lt;/span&gt;&lt;span class="lnt"&gt; 29
&lt;/span&gt;&lt;span class="lnt"&gt; 30
&lt;/span&gt;&lt;span class="lnt"&gt; 31
&lt;/span&gt;&lt;span class="lnt"&gt; 32
&lt;/span&gt;&lt;span class="lnt"&gt; 33
&lt;/span&gt;&lt;span class="lnt"&gt; 34
&lt;/span&gt;&lt;span class="lnt"&gt; 35
&lt;/span&gt;&lt;span class="lnt"&gt; 36
&lt;/span&gt;&lt;span class="lnt"&gt; 37
&lt;/span&gt;&lt;span class="lnt"&gt; 38
&lt;/span&gt;&lt;span class="lnt"&gt; 39
&lt;/span&gt;&lt;span class="lnt"&gt; 40
&lt;/span&gt;&lt;span class="lnt"&gt; 41
&lt;/span&gt;&lt;span class="lnt"&gt; 42
&lt;/span&gt;&lt;span class="lnt"&gt; 43
&lt;/span&gt;&lt;span class="lnt"&gt; 44
&lt;/span&gt;&lt;span class="lnt"&gt; 45
&lt;/span&gt;&lt;span class="lnt"&gt; 46
&lt;/span&gt;&lt;span class="lnt"&gt; 47
&lt;/span&gt;&lt;span class="lnt"&gt; 48
&lt;/span&gt;&lt;span class="lnt"&gt; 49
&lt;/span&gt;&lt;span class="lnt"&gt; 50
&lt;/span&gt;&lt;span class="lnt"&gt; 51
&lt;/span&gt;&lt;span class="lnt"&gt; 52
&lt;/span&gt;&lt;span class="lnt"&gt; 53
&lt;/span&gt;&lt;span class="lnt"&gt; 54
&lt;/span&gt;&lt;span class="lnt"&gt; 55
&lt;/span&gt;&lt;span class="lnt"&gt; 56
&lt;/span&gt;&lt;span class="lnt"&gt; 57
&lt;/span&gt;&lt;span class="lnt"&gt; 58
&lt;/span&gt;&lt;span class="lnt"&gt; 59
&lt;/span&gt;&lt;span class="lnt"&gt; 60
&lt;/span&gt;&lt;span class="lnt"&gt; 61
&lt;/span&gt;&lt;span class="lnt"&gt; 62
&lt;/span&gt;&lt;span class="lnt"&gt; 63
&lt;/span&gt;&lt;span class="lnt"&gt; 64
&lt;/span&gt;&lt;span class="lnt"&gt; 65
&lt;/span&gt;&lt;span class="lnt"&gt; 66
&lt;/span&gt;&lt;span class="lnt"&gt; 67
&lt;/span&gt;&lt;span class="lnt"&gt; 68
&lt;/span&gt;&lt;span class="lnt"&gt; 69
&lt;/span&gt;&lt;span class="lnt"&gt; 70
&lt;/span&gt;&lt;span class="lnt"&gt; 71
&lt;/span&gt;&lt;span class="lnt"&gt; 72
&lt;/span&gt;&lt;span class="lnt"&gt; 73
&lt;/span&gt;&lt;span class="lnt"&gt; 74
&lt;/span&gt;&lt;span class="lnt"&gt; 75
&lt;/span&gt;&lt;span class="lnt"&gt; 76
&lt;/span&gt;&lt;span class="lnt"&gt; 77
&lt;/span&gt;&lt;span class="lnt"&gt; 78
&lt;/span&gt;&lt;span class="lnt"&gt; 79
&lt;/span&gt;&lt;span class="lnt"&gt; 80
&lt;/span&gt;&lt;span class="lnt"&gt; 81
&lt;/span&gt;&lt;span class="lnt"&gt; 82
&lt;/span&gt;&lt;span class="lnt"&gt; 83
&lt;/span&gt;&lt;span class="lnt"&gt; 84
&lt;/span&gt;&lt;span class="lnt"&gt; 85
&lt;/span&gt;&lt;span class="lnt"&gt; 86
&lt;/span&gt;&lt;span class="lnt"&gt; 87
&lt;/span&gt;&lt;span class="lnt"&gt; 88
&lt;/span&gt;&lt;span class="lnt"&gt; 89
&lt;/span&gt;&lt;span class="lnt"&gt; 90
&lt;/span&gt;&lt;span class="lnt"&gt; 91
&lt;/span&gt;&lt;span class="lnt"&gt; 92
&lt;/span&gt;&lt;span class="lnt"&gt; 93
&lt;/span&gt;&lt;span class="lnt"&gt; 94
&lt;/span&gt;&lt;span class="lnt"&gt; 95
&lt;/span&gt;&lt;span class="lnt"&gt; 96
&lt;/span&gt;&lt;span class="lnt"&gt; 97
&lt;/span&gt;&lt;span class="lnt"&gt; 98
&lt;/span&gt;&lt;span class="lnt"&gt; 99
&lt;/span&gt;&lt;span class="lnt"&gt;100
&lt;/span&gt;&lt;span class="lnt"&gt;101
&lt;/span&gt;&lt;span class="lnt"&gt;102
&lt;/span&gt;&lt;span class="lnt"&gt;103
&lt;/span&gt;&lt;span class="lnt"&gt;104
&lt;/span&gt;&lt;span class="lnt"&gt;105
&lt;/span&gt;&lt;span class="lnt"&gt;106
&lt;/span&gt;&lt;span class="lnt"&gt;107
&lt;/span&gt;&lt;span class="lnt"&gt;108
&lt;/span&gt;&lt;span class="lnt"&gt;109
&lt;/span&gt;&lt;span class="lnt"&gt;110
&lt;/span&gt;&lt;span class="lnt"&gt;111
&lt;/span&gt;&lt;span class="lnt"&gt;112
&lt;/span&gt;&lt;span class="lnt"&gt;113
&lt;/span&gt;&lt;span class="lnt"&gt;114
&lt;/span&gt;&lt;span class="lnt"&gt;115
&lt;/span&gt;&lt;span class="lnt"&gt;116
&lt;/span&gt;&lt;span class="lnt"&gt;117
&lt;/span&gt;&lt;span class="lnt"&gt;118
&lt;/span&gt;&lt;span class="lnt"&gt;119
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * this pointer should be put into the header file,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * so other modules can access this class.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;zend_class_entry&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;c_leigh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* just a simple method. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters_none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;php_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World !&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* getting handle of this object. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getObjectHandle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters_none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getThis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;RETURN_LONG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Z_OBJ_HANDLE_P&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* get value of the property &amp;#39;bloodType&amp;#39; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getBloodType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;blood_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters_none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getThis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;blood_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zend_read_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c_leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bloodType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;bloodType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;RETURN_ZVAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blood_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* set value of the property &amp;#39;bloodType&amp;#39; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setBloodType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zend_parse_parameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ZEND_NUM_ARGS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;z&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FAILURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getThis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;zend_update_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c_leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bloodType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;bloodType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_value&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;zend_function_entry&lt;/span&gt; &lt;span class="n"&gt;leigh_functions&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;PHP_ME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ZEND_ACC_PUBLIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;PHP_ME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getObjectHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ZEND_ACC_PUBLIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;PHP_ME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getBloodType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ZEND_ACC_PUBLIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;PHP_ME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setBloodType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ZEND_ACC_PUBLIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* PHP_ABSTRACT_ME(Leigh, abstractMethod, NULL) // abstract method */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PHP_FE_END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * create a new class inheriting Leigh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;zend_class_entry&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;c_hero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * create an interface
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;zend_class_entry&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;i_superman&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;zend_function_entry&lt;/span&gt; &lt;span class="n"&gt;superman_functions&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;PHP_ABSTRACT_ME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ISuperman&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saveEarth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PHP_FE_END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* PHP_MINIT_FUNCTION
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;PHP_MINIT_FUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;donie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* If you have INI entries, uncomment these lines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; REGISTER_INI_ENTRIES();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time_of_minit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* register a class */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_class_entry&lt;/span&gt; &lt;span class="n"&gt;tmp_leigh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;INIT_CLASS_ENTRY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Leigh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leigh_functions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;c_leigh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zend_register_internal_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tmp_leigh&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* declare a property initialized as null */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;zend_declare_property_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c_leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bloodType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;bloodType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ZEND_ACC_PUBLIC&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* declare a class constant */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;zend_declare_class_constant_double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c_leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;PI&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;PI&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.1415926&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* declare an interface */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_class_entry&lt;/span&gt; &lt;span class="n"&gt;tmp_superman&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;INIT_CLASS_ENTRY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_superman&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ISuperman&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;superman_functions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i_superman&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zend_register_internal_interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tmp_superman&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* inherit a class and implement an interface*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_class_entry&lt;/span&gt; &lt;span class="n"&gt;tmp_hero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;INIT_CLASS_ENTRY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_hero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hero&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;c_hero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zend_register_internal_class_ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tmp_hero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c_leigh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;zend_class_implements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c_hero&lt;/span&gt; &lt;span class="n"&gt;TSRMLS_CC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i_superman&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="方法修饰符"&gt;方法修饰符&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;ZEND_ACC_PUBLIC&lt;br&gt;
ZEND_ACC_PROTECTED&lt;br&gt;
ZEND_ACC_PRIVATE&lt;br&gt;
ZEND_ACC_STATIC&lt;br&gt;
ZEND_ACC_FINAL&lt;br&gt;
ZEND_ACC_ABSTRACT&lt;/p&gt;</description></item><item><title>变形金刚：俺钢锁才是老大</title><link>http://0x3f.org/posts/transformers-grim-lock/</link><pubDate>Sun, 26 Apr 2015 20:55:00 +0000</pubDate><guid>http://0x3f.org/posts/transformers-grim-lock/</guid><description>&lt;p&gt;变形金刚是工业艺术的巅峰之作。不仅仅是怀旧和补童年。&lt;strong&gt;理工宅两大图腾，恐龙和机器人。从没有一个东西像汽车人恐龙部队一样，把这两样完美地融为一体。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;孩之宝的东西很多时候不尽如人意，价格又太贵。有一些第三方的仿品，不乏精品。像威将的这个钢锁，是孩之宝V级的放大版，几乎与L级等身，头部和大腿根部是合金部件，很有质感。有美版和黑暗两个涂装，结合放大后的形象，黑暗涂装更显霸气。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EBG8vXei/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;美版L级人形。整体精致，但是太瘦，两条腿细得跟小儿麻痺似的，盈盈一掬的小蛮腰，这是要走长腿欧巴路线啊。这个比例，如果放大一号效果会更好，不过钢锁老大比其它L级大一号不是理所当然的么。最讨厌的是电镀，又俗又易脱落。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EBG8wf4l/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;美版L级龙形。非常失败。身体比例失调，趴耳朵，塌脊梁，短尾巴。不忍直视。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EBG8wIB3/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;祖国版V级人形。V级钢锁是不以人形见长的，不过放大后观感尚可。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EBG8x7KX/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;祖国版V级龙形。V级钢锁的龙形完爆L级，体形霸气，立耳，隆背，翘尾。孩版V级最大的遗憾就是体形太小，祖国版龙形堪称完美。&lt;/p&gt;
&lt;p&gt;不知道是不是我中奖了，祖国版人形的大腿根部虽然是球齿关节，但是球齿无效，关节比较松，容易劈叉。不过这个做工、用料，只要几十软妹币，相对几倍价格的孩版来说，威将良心之作啊。&lt;/p&gt;</description></item><item><title>PHP数组的实现与操作</title><link>http://0x3f.org/posts/array-implementation-in-php/</link><pubDate>Fri, 24 Apr 2015 12:09:00 +0000</pubDate><guid>http://0x3f.org/posts/array-implementation-in-php/</guid><description>&lt;h2 id="存储结构"&gt;存储结构&lt;/h2&gt;
&lt;p&gt;和其它变量一样，PHP的数组也是一个zval。存储数据的哈希表存放在zval-&amp;gt;value-&amp;gt;ht中。&lt;/p&gt;
&lt;h2 id="符号表操作"&gt;符号表操作&lt;/h2&gt;
&lt;p&gt;为实现可转换成整数的字符串键与整数键指向同一个元素，在哈希表操作的基础上封装了一层，对可转换成整数的字符串键转换成整数，然后调用zend_hash_index_*操作，否则调用zend_hash_*操作。这就是符号表操作。&lt;/p&gt;
&lt;p&gt;用ZEND_HANDLE_NUMERIC处理整数字符串键：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;zend_symtable_find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HashTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;pData&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ZEND_HANDLE_NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;zend_hash_index_find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pData&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;zend_hash_find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其它符号表操作函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;zend_symtable_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HashTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;zend_symtable_del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HashTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;zend_symtable_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HashTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nDataSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;pDest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;zend_symtable_update_current_key_ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HashTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HashPosition&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="数组操作"&gt;数组操作&lt;/h2&gt;
&lt;h3 id="初始化"&gt;初始化&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 初始化数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;zv1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;array_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zv1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 初始化数组并指定哈希表nTableSize的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;array_init_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zv1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 在函数中返回数组：把返回值初始化为数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;array_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="插入和更新"&gt;插入和更新&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Insert at next index */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;add_next_index_&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Insert at specific index */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;add_index_&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Insert at specific key */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;add_assoc_&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Insert at specific key of length key_len (for binary safety) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;add_assoc_&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;_ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;key_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;星号表示类型名，可用类型名如下：&lt;/p&gt;</description></item><item><title>PHP哈希表的实现与操作</title><link>http://0x3f.org/posts/hashtable-implementation-of-php/</link><pubDate>Thu, 23 Apr 2015 15:56:00 +0000</pubDate><guid>http://0x3f.org/posts/hashtable-implementation-of-php/</guid><description>&lt;h2 id="结构"&gt;结构&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 哈希表结构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;_hashtable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nTableSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nTableMask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nNumOfElements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 全部元素数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;nNextFreeElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 下一个可用的整数键
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pInternalPointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 枚举操作时使用，指向当前Bucket
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pListHead&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pListTail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Bucket&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;arBuckets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;dtor_func_t&lt;/span&gt; &lt;span class="n"&gt;pDestructor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 元素的析构函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_bool&lt;/span&gt; &lt;span class="n"&gt;persistent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 是否在本次请求结束后保留哈希表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;nApplyCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 循环级别，防止循环引用导致遍历哈希表时死循环
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zend_bool&lt;/span&gt; &lt;span class="n"&gt;bApplyProtection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 是否防止死循环
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#if ZEND_DEBUG
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;inconsistent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;HashTable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Bucket结构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;nKeyLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pDataPtr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pListNext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pListLast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pNext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pLast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="哈希冲突处理"&gt;哈希冲突处理&lt;/h3&gt;
&lt;p&gt;哈希表通过计算键值的哈希值，将对应的数据映射到对应的槽上。理论上会存在不同的键的哈希值相同的情况。&lt;/p&gt;</description></item><item><title>自动重映射键盘</title><link>http://0x3f.org/posts/auto-remap-keyboard/</link><pubDate>Fri, 17 Apr 2015 18:02:00 +0000</pubDate><guid>http://0x3f.org/posts/auto-remap-keyboard/</guid><description>&lt;p&gt;每次键盘拔出再插入时，键盘映射都会失效，要重新执行映射，而且要对不同的键盘应用不同的映射方案。试过直接添加udev规则，即使指定X Display和Xauthority也不成功。所以用pyudev写个脚本（&lt;a href="https://github.com/xbot/shell/blob/master/udev.py"&gt;最新版本&lt;/a&gt;）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;span class="lnt"&gt;68
&lt;/span&gt;&lt;span class="lnt"&gt;69
&lt;/span&gt;&lt;span class="lnt"&gt;70
&lt;/span&gt;&lt;span class="lnt"&gt;71
&lt;/span&gt;&lt;span class="lnt"&gt;72
&lt;/span&gt;&lt;span class="lnt"&gt;73
&lt;/span&gt;&lt;span class="lnt"&gt;74
&lt;/span&gt;&lt;span class="lnt"&gt;75
&lt;/span&gt;&lt;span class="lnt"&gt;76
&lt;/span&gt;&lt;span class="lnt"&gt;77
&lt;/span&gt;&lt;span class="lnt"&gt;78
&lt;/span&gt;&lt;span class="lnt"&gt;79
&lt;/span&gt;&lt;span class="lnt"&gt;80
&lt;/span&gt;&lt;span class="lnt"&gt;81
&lt;/span&gt;&lt;span class="lnt"&gt;82
&lt;/span&gt;&lt;span class="lnt"&gt;83
&lt;/span&gt;&lt;span class="lnt"&gt;84
&lt;/span&gt;&lt;span class="lnt"&gt;85
&lt;/span&gt;&lt;span class="lnt"&gt;86
&lt;/span&gt;&lt;span class="lnt"&gt;87
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ch"&gt;#!/usr/bin/env python2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# encoding: utf-8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;File: udev.py
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;Description: udev monitor script.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;Author: Donie Leigh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;Email: donie.leigh at gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;glib&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pyudev&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Monitor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PID_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/tmp/udev_monitor.pid&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remap_pokerii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34; Do keyboard remapping when PokerII is plugged in.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ID_VENDOR_ID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0f39&amp;#39;&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;add&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;setxkbmap&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;xmodmap ~/.Xmodmap&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remap_filco&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34; Do keyboard remapping when Filco is plugged in.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ID_VENDOR_ID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;04d9&amp;#39;&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;add&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;setxkbmap&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;xmodmap ~/.Xmodmap&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_pid_running&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34; Check if the given pid is running.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :pid: int
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :returns: bool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_pid_or_die&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34; Write the current pid into pid file or exists if there is already a instance running.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :returns: void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PID_FILE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PID_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_pid_running&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Process &lt;/span&gt;&lt;span class="si"&gt;{0}&lt;/span&gt;&lt;span class="s2"&gt; is still running.&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;SystemExit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PID_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PID_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pyudev.glib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MonitorObserver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;device_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;remap_pokerii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;remap_filco&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pyudev.glib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GUDevMonitorObserver&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;MonitorObserver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;device_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;remap_pokerii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;remap_filco&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;monitor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Monitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_netlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;usb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MonitorObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;device-event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device_event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;glib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MainLoop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;write_pid_or_die&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Game over.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;有个坑，监测到键盘插入事件后要等一秒再应用映射，否则不成功。&lt;/p&gt;</description></item><item><title>用树苺派做家庭监控</title><link>http://0x3f.org/posts/monitor-home-with-raspberry-pi/</link><pubDate>Tue, 07 Apr 2015 10:56:00 +0000</pubDate><guid>http://0x3f.org/posts/monitor-home-with-raspberry-pi/</guid><description>&lt;p&gt;用树苺派做视频监控，当视野内有物体移动时，自动拍照、录视频、同步到远程主机，并提醒到远程电脑和手机。&lt;/p&gt;
&lt;h2 id="用motion做视频监控"&gt;用Motion做视频监控&lt;/h2&gt;
&lt;p&gt;安装Motion，修改几项必要的配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 照片和视频存储路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;target_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/media/sda1/cam&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 允许局域网内其它主机访问视频&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;webcam_localhost off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 监测到移动物体时，创建作为标识的临时文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;on_event_start &amp;#34;echo 1 &amp;gt; /tmp/invasion_detected&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 移动物体消失时，移除临时文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;on_event_end &amp;#34;rm /tmp/invasion_detected&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 监测到移动物体并在保存第一张照片时，发送提醒到电脑和手机&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;on_picture_save [ -f /tmp/invasion_detected ] &amp;amp;&amp;amp; [ `cat /tmp/invasion_detected` -gt 0 ] &amp;amp;&amp;amp; echo 0 &amp;gt; /tmp/invasion_detected &amp;amp;&amp;amp; proxychains /root/SmartHome/script/alert.py -f %f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="用lsyncd同步到vps"&gt;用Lsyncd同步到VPS&lt;/h2&gt;
&lt;p&gt;安装lsyncd并配置：&lt;/p&gt;</description></item><item><title>用树苺派搭NAS</title><link>http://0x3f.org/posts/make-nas-with-raspberry-pi/</link><pubDate>Fri, 03 Apr 2015 15:13:00 +0000</pubDate><guid>http://0x3f.org/posts/make-nas-with-raspberry-pi/</guid><description>&lt;p&gt;为了让盒子能直接播放&lt;a href="http://0x3f.org/post/remote-downloading-with-raspberry-pi/"&gt;远程下载&lt;/a&gt;的电影，继续在树苺派上搭NAS。&lt;/p&gt;
&lt;p&gt;安装samba，然后配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[nas]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/media/sda1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;valid users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@users&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;force group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;users&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;create mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;0660&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;directory mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;0771&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;read only&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;把Linux用户添加到samba并设置密码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;smbpasswd -a pi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;盒子上的Kodi硬解有问题，用ES+MX Player替代。电脑上用Kodi。&lt;/p&gt;</description></item><item><title>再次调整磁盘分区</title><link>http://0x3f.org/posts/adjust-disk-partitions-again/</link><pubDate>Fri, 03 Apr 2015 14:44:00 +0000</pubDate><guid>http://0x3f.org/posts/adjust-disk-partitions-again/</guid><description>&lt;p&gt;自从&lt;a href="http://0x3f.org/post/adjust-disk-partitions-in-archlinux/"&gt;上次&lt;/a&gt;调整磁盘分区，一直把根目录和主目录分别挂在一个物理分区下，即使系统挂了或者换发行版也不影响主目录。最近根分区很紧张，干脆把两个分区合并了。&lt;/p&gt;
&lt;p&gt;先用UNetBootin安装Puppy Linux到U盘，需要手工修改U盘里的syslinux.cfg，把“pmedia=&lt;strong&gt;cd&lt;/strong&gt;”改成“pmedia=&lt;strong&gt;usbflash&lt;/strong&gt;”，然后用U盘启动。&lt;/p&gt;
&lt;p&gt;把主目录的内容完整复制到移动硬盘：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 挂载主目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir /mnt/oldhome
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount -t ext4 /dev/sda2 /mnt/oldhome
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 挂载移动硬盘&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir /mnt/bakdisk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount -t ext4 /dev/sdc1 /mnt/bakdisk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 复制主目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp -a /mnt/oldhome /mnt/bakdisk/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 取消挂载主目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;umount /mnt/oldhome
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;用gparted删除主目录分区，合并到根分区。然后恢复主目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 挂载根分区&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir /mnt/newroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount -t ext4 /dev/sda1 /mnt/newroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 恢复主目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp -a /mnt/bakdisk/* /mnt/newroot/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 修改fstab，取消主目录的挂载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vim /mnt/newroot/etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 取消挂载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;umount /mnt/bakdisk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;umount /mnt/newroot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>这段时间读的几本书</title><link>http://0x3f.org/posts/books-i-read-these-days/</link><pubDate>Sun, 29 Mar 2015 16:00:00 +0000</pubDate><guid>http://0x3f.org/posts/books-i-read-these-days/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ExoJe1q2/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;每个危楼听雨的暮年都有过软红十丈的青春。文字凄艳，明清小品里的上乘之作。后两记文风模仿前文，意境远逊，应是伪作，可以不读。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ExoJbmLN/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;上部是政治史，下部是文化史。文化史部分很好，涨知识，应该买本经常翻翻。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ExoJdozU/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;大部分是讲稿，内容不系统，不适合入门。畅销书不可信啊。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/ExoJdmOb/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;科普书，不知道豆瓣上那么高的评分哪儿来的。&lt;/p&gt;</description></item><item><title>用树苺派实现远程下载</title><link>http://0x3f.org/posts/remote-downloading-with-raspberry-pi/</link><pubDate>Sat, 28 Mar 2015 19:14:00 +0000</pubDate><guid>http://0x3f.org/posts/remote-downloading-with-raspberry-pi/</guid><description>&lt;p&gt;远程用树苺派利用空闲时间下载大文件，需要百度云、aria2和VPS。因为网络运营商给的IP不是真的公网IP，而且免费的动态域名服务不稳定，所以用VPS把树苺派上的端口转发到外网。&lt;/p&gt;
&lt;h2 id="树苺派"&gt;树苺派&lt;/h2&gt;
&lt;p&gt;在树苺派上部署aria2下载服务，并发布到VPS。&lt;/p&gt;
&lt;p&gt;安装aria2，创建以下配置文件，修改/media/sda1为实际下载目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/media/sda1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;file-allocation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;prealloc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;log-level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#log-level=debug&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;max-connection-per-server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;summary-interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;120&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;daemon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;enable-rpc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;rpc-listen-port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;6800&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;rpc-listen-all&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;max-concurrent-downloads&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;save-session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/etc/aria2/save-session.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;input-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/etc/aria2/save-session.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/media/sda1/aria.log&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;disable-ipv6&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;disk-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;25M&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;retry-wait&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;max-tries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;user-agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;netdisk;4.4.0.6;PC;PC-Windows;6.2.9200;WindowsBaiduYunGuanJia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;我的树苺派用Archlinux，创建systemd的服务配置文件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;aria2c -- file download manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;forking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;%i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;%h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;VAR=/var/%i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/aria2c --daemon --enable-rpc --rpc-listen-all --rpc-allow-origin-all -c -D --conf-path=/etc/aria2/aria2.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;激活并启动aria2服务。&lt;/p&gt;</description></item><item><title>运行时可装卸的Mixin的PHP实现</title><link>http://0x3f.org/posts/php-implementation-of-runtime-mixin/</link><pubDate>Thu, 04 Dec 2014 11:52:00 +0000</pubDate><guid>http://0x3f.org/posts/php-implementation-of-runtime-mixin/</guid><description>&lt;p&gt;PHP的Trait可以实现加载时（load time）的混入（mixin）。作为元编程的一部分，运行时（run time）的混入拥有更大的灵活性。下面利用PHP的魔术方法实现运行时的混入。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 支持混入的类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 所有混入的实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$_behaviors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 魔术方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $name 方法名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param array $arguments 参数数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return mixed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @throws MethodNotFoundException
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_behaviors&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;call_user_func_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MethodNotFoundException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 魔术方法，从混入对象实例中取属性值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $attrName 属性名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return mixed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @throws AttrNotFoundException
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attrName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_behaviors&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$attrName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$attrName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AttributeNotFoundException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;$attrName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 附加混入对象实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param object $behavior 混入对象实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $name 混入对象实例名称
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;attachBehavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_behaviors&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_behaviors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$behavior&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 卸载混入对象实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $name 混入对象实例名称
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;detachBehavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_behaviors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 混入类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Behavior&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 将本实例混入指定对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param object $object 支持混入的实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $name 目标对象存储本混入对象实例的键值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @throws BehaviorNotAttachableException
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mixin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;attachBehavior&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;call_user_func_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;attachBehavior&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorNotAttachableException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$object&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;使用示例：&lt;/p&gt;</description></item><item><title>读完《湘行散记》</title><link>http://0x3f.org/posts/after-reading-sketches-of-the-travel-to-hunan/</link><pubDate>Sat, 29 Nov 2014 20:17:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-sketches-of-the-travel-to-hunan/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/EfaDoeOo/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;能让我这个不喜欢读散文的人坚持读完的，是枕著一叶扁舟、听著潺潺流水、忖著多年后的自己——身在何方、心念何人、情系何物……&lt;/p&gt;</description></item><item><title>Phalcon项目中PHPUnit的初始化</title><link>http://0x3f.org/posts/testing-with-phpunit-in-phalcon/</link><pubDate>Sat, 29 Nov 2014 09:58:00 +0000</pubDate><guid>http://0x3f.org/posts/testing-with-phpunit-in-phalcon/</guid><description>&lt;p&gt;参考&lt;a href="http://docs.phalconphp.com/zh/latest/reference/unit-testing.html"&gt;官方文档&lt;/a&gt;，稍作修改。&lt;/p&gt;
&lt;p&gt;在项目下创建目录 unittests ，进入目录执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;composer require phpunit/phpunit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;创建 tests 目录并在其中创建文件 Bootstrap.php ：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Phalcon\DI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Phalcon\DI\FactoryDefault&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;ini_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;display_errors&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;error_reporting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;E_ALL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ROOT_PATH&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PROJECT_DIR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/home/taoqi/workspace&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;set_include_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ROOT_PATH&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;PATH_SEPARATOR&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;get_include_path&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// required for phalcon/incubator
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="no"&gt;__DIR__&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/../vendor/autoload.php&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 加载项目文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nx"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/web/config/config.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nx"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/web/config/loader.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$loader&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;registerDirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ROOT_PATH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// $di = new FactoryDefault();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;DI&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// add any needed services to the DI here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nx"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/web/config/services.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;DI&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;setDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$di&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;安装 phalcon 的 phpunit 辅助库：&lt;/p&gt;</description></item><item><title>用好代码时光机</title><link>http://0x3f.org/posts/leverage-code-time-machine/</link><pubDate>Fri, 21 Nov 2014 23:19:00 +0000</pubDate><guid>http://0x3f.org/posts/leverage-code-time-machine/</guid><description>&lt;p&gt;今天看了篇文章，讲几种常见的、糟糕的注释用法。其中之一是把废弃的代码注释起来，而不是直接删掉，原因是担心以后可能会用。&lt;/p&gt;
&lt;p&gt;这个其实就是版本控制系统（VCS）要解决的问题之一。包括对于团队协作的项目，经常需要看某段代码是谁改的、什么时间、什么原因。都是可以用VCS很方便地解决的问题。&lt;/p&gt;
&lt;p&gt;我以前是用二分法在提交列表里找的。其实有更好的解决方法，思路是列出源码在历次提交中修改的内容，然后在其中查找要找的东西就行了。&lt;/p&gt;
&lt;p&gt;git的解决方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git log -p abc.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;svn的解决方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;svn log --diff --internal-diff abc.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;vim的辅助函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Show commit history of the current file under the given VCS in a new window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;ShowCommitHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt; &amp;#34; Check parameter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;vcs&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;svn&amp;#39;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;vcs&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;git&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;echoerr&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Unknow VCS: &amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;vcs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt; &amp;#34; Do the dirty work&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exe&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;new&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;vcs&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;svn&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exe&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;r !svn log --diff --internal-diff &amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;fileName&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;vcs&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;git&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exe&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;r !git log -p &amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;fileName&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;File not found.&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;ssch&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ShowCommitHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;svn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;gsch&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ShowCommitHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>开始用在线Markdown编辑器记笔记</title><link>http://0x3f.org/posts/start-taking-note-in-online-markdown-editor/</link><pubDate>Thu, 20 Nov 2014 22:35:00 +0000</pubDate><guid>http://0x3f.org/posts/start-taking-note-in-online-markdown-editor/</guid><description>&lt;p&gt;开始用支持VIM模式的在线Markdown编辑器记笔记。既非鼠辈（&lt;em&gt;鼠标依赖症不治者&lt;/em&gt;），始终忍受不了其它WYSIWYG（所见即所得）的在线笔记。&lt;/p&gt;
&lt;p&gt;大部分在线笔记最傻X的一点是，必须点一下编辑按钮才能开始写东西。支持VIM模式的笔记就不用说了，丝般顺滑，不是我大Vimer就不会懂个中骚柔。&lt;/p&gt;
&lt;p&gt;组织上一向后知后觉。智能手机刚开始的时候，组织上很不感冒，理由是屏幕易碎、电池难支&lt;del&gt;、冯唐易老、李广难封&lt;/del&gt;。而今现在眼目下，一日不搞机，如隔三秋。在线Markdown编辑器出现也有段时间了，一直觉得这货无非就是给Markdown加了个可笑的准WYSIWYG，现在看来，真是做笔记的不二神器，罪过罪过。&lt;/p&gt;
&lt;p&gt;说说组织上跟Markdown的故事。很久很久以前，博客刚开始流行的时候，组织上开始写博客，和大部分人一样，注册个账号写公开日记，很快就忍受不了WYSIWYG编辑器失控的格式，于是开始手写HTML代码，很快就发现这货真TM反人类，从此恨乌及乌至今最讨厌的数据交换格式还是XML，于是自定几种格式或标记，用Java写了个解析工具，把文章源码翻译成HTML。突然有天发现这个星球上居然有种叫轻量型标记语言的东西，干的就是这么个事，只不过我的那些标记和解析工具又丑又烂而已。试了几种之后，最终选了Markdown，从此举案齐眉云云。&lt;/p&gt;</description></item><item><title>Vim强制在PHP中使用HTML注释的方法</title><link>http://0x3f.org/posts/force-commenting-html-in-php-files-in-vim/</link><pubDate>Thu, 13 Nov 2014 21:45:00 +0000</pubDate><guid>http://0x3f.org/posts/force-commenting-html-in-php-files-in-vim/</guid><description>&lt;p&gt;对PHP页面模板中的HTML做注释，NERDCommenter是根据文件类型处理的，所以必须临时转换文件类型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; 强制使用HTML的注释&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;ForceHTMLComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;execute&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;firstline&lt;/span&gt;.&lt;span class="s2"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;.&lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;lastline&lt;/span&gt;.&lt;span class="s2"&gt;&amp;#34;call NERDComment(\&amp;#34;x\&amp;#34;, \&amp;#34;&amp;#34;&lt;/span&gt;.&lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;type&lt;/span&gt;.&lt;span class="s2"&gt;&amp;#34;\&amp;#34;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Sexy&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;normal&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;cs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;normal&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;cc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;fhcc&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ForceHTMLComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Comment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;vmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;fhcc&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ForceHTMLComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Comment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;fhcs&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ForceHTMLComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Sexy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;vmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;fhcs&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ForceHTMLComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Sexy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;fhcu&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ForceHTMLComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Uncomment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;vmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;fhcu&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;ForceHTMLComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Uncomment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;有日子没写vimscript了，手都生了。&lt;/p&gt;</description></item><item><title>ZSH下新安装的程序无法自动补全的解决方法</title><link>http://0x3f.org/posts/how-to-auto-complete-newly-installed-command-in-zsh/</link><pubDate>Wed, 12 Nov 2014 22:15:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-auto-complete-newly-installed-command-in-zsh/</guid><description>&lt;p&gt;Zsh默认开启了对PATH变量的缓存，这是导致新安装的程序无法立即使用自动补全的原因。&lt;/p&gt;
&lt;p&gt;其实只要PATH变量不太复杂，安装的程序不太多，完全没必要开启缓存，实际上我把缓存关掉后完全没有感觉到补全的速度有什么变化。&lt;/p&gt;
&lt;p&gt;方法如下，在.zshrc中增加一行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zstyle &lt;span class="s1"&gt;&amp;#39;:completion:*&amp;#39;&lt;/span&gt; rehash &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;也可以在必要的时间手工执行命令&lt;strong&gt;rehash&lt;/strong&gt;，也是个临时解决方法。&lt;/p&gt;</description></item><item><title>接管PHP致命错误的方法</title><link>http://0x3f.org/posts/how-to-take-over-php-fatal-error-handling/</link><pubDate>Wed, 12 Nov 2014 00:47:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-take-over-php-fatal-error-handling/</guid><description>&lt;p&gt;Yii 2.0引入了一项新特性，可以接管PHP的致命错误。在此之前，如果PHP源码有语法错误，框架本身是不会处理的。&lt;/p&gt;
&lt;p&gt;实现的思路如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;禁止显示错误&lt;/li&gt;
&lt;li&gt;注册自定义的shutdown回调函数&lt;/li&gt;
&lt;li&gt;在回调函数中获取最近的错误&lt;/li&gt;
&lt;li&gt;若错误是致命错误，调用相应的处理逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;ini_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;display_errors&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;register_shutdown_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error_get_last&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;E_ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;E_PARSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E_CORE_ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E_CORE_WARNING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E_COMPILE_ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E_COMPILE_WARNING&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ob_clean&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;pre&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;/pre&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>读完《黑客与画家》</title><link>http://0x3f.org/posts/after-reading-hackers-and-painters/</link><pubDate>Sun, 26 Oct 2014 10:06:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-hackers-and-painters/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E9VYTLb7/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;身兼技术牛人和创业成功者两个身份，自然有资格指点江山，有些观点很自负，有些观点对人有启发。作者很推崇Lisp，很不屑Java。&lt;/p&gt;</description></item><item><title>读完《MongoDB权威指南》第二版</title><link>http://0x3f.org/posts/after-reading-mongodb-the-definitive-guide/</link><pubDate>Sun, 26 Oct 2014 10:01:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-mongodb-the-definitive-guide/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E9VWUjut/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;第二版比第一版补充了很多内容，介绍得很详细，是学习mongodb的好书。&lt;/p&gt;
&lt;p&gt;但是翻译版有很多印刷错误，个别译句也有问题。&lt;/p&gt;</description></item><item><title>读完《冰与火之歌》卷一</title><link>http://0x3f.org/posts/after-reading-a-song-of-ice-and-fire-v1/</link><pubDate>Sun, 26 Oct 2014 09:56:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-a-song-of-ice-and-fire-v1/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E9VUK2P1/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;读了一部分，还是不怎么喜欢西方中世纪文化，最后改看电视剧，拍得也很一般。&lt;/p&gt;</description></item><item><title>读完《城南旧事》</title><link>http://0x3f.org/posts/after-reading-my-memories-of-old-beijing/</link><pubDate>Sun, 26 Oct 2014 09:40:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-my-memories-of-old-beijing/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E9VO58ag/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;描写民国时北京南城市民生活很生动，但是以儿童的视角叙事显得揣着明白装糊涂。&lt;/p&gt;</description></item><item><title>读完《边城》</title><link>http://0x3f.org/posts/after-reading-border-town/</link><pubDate>Sun, 26 Oct 2014 09:32:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-border-town/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E9VMRoII/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;文章写得很美，本打算十一去茶峒，看看顺顺吊脚楼，坐坐白塔下的拉拉渡，临时改了行程，只能以后有空再去了。&lt;/p&gt;</description></item><item><title>放弃《一座城池》和《天才在左疯子在右》</title><link>http://0x3f.org/posts/give-up-the-ideal-city-and-genius-and-madman/</link><pubDate>Sun, 26 Oct 2014 09:30:00 +0000</pubDate><guid>http://0x3f.org/posts/give-up-the-ideal-city-and-genius-and-madman/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E9VPP5J0/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;现在不喜欢这种书了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E9VOUOtx/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;内心不够强大，再看下去我就疯了。&lt;/p&gt;</description></item><item><title>读完《中国大历史》</title><link>http://0x3f.org/posts/after-reading-big-history-of-china/</link><pubDate>Fri, 12 Sep 2014 23:07:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-big-history-of-china/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E3k8bFJc/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;偏学术，比较抽象，不如《万历十五年》好看。&lt;/p&gt;</description></item><item><title>读完《中国历代政治得失》</title><link>http://0x3f.org/posts/after-reading-political-gain-and-loss-of-china/</link><pubDate>Sun, 31 Aug 2014 23:19:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-political-gain-and-loss-of-china/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/E1v1Ohh6/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;钱穆有文侠风，读这本书，能看到这样一个影子，上马击狂胡，下马草军书。他也是个民族主义者，提到元清，几乎没一句好话。所以要贯通国史，还得多读读别的书。总体来说，读这本书时常感醍醐灌顶，为习国史者必读。&lt;/p&gt;</description></item><item><title>读完《中国史纲》</title><link>http://0x3f.org/posts/after-reading-brief-history-of-china/</link><pubDate>Wed, 20 Aug 2014 22:30:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-brief-history-of-china/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DZOYRqbR/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;自序中对治史的方法论让我受益匪浅，本书语气平和、娓娓道来，像讲故事一样讲历史，但又严谨、广博、不肤浅，风格和其它史书大不一样，我一直理想中的史书就是这样，不要给历史背太重的包袱，不要带著一定要学点什么的目的读历史。&lt;/p&gt;
&lt;p&gt;本书的缺点是详略失当。有些地方太简略，比如匈奴的衰落，五单于争立一笔带过。有些地方太详细，鸿门宴几乎是史记的译文。作为一部通史，应该有大历史观，能站在较高的层面上把历史的脉络梳理清楚。&lt;/p&gt;</description></item><item><title>读完《庄子今注今译》</title><link>http://0x3f.org/posts/after-reading-zhuangzi-jin-zhu-jin-yi/</link><pubDate>Sun, 17 Aug 2014 18:36:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-zhuangzi-jin-zhu-jin-yi/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DZl9Hgeh/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;很好的注本，有些字句的翻译有点儿晦涩。庄子的思想超越了老子，想把庄子的思想理解透彻很难。&lt;/p&gt;</description></item><item><title>Project Euler Problem 25 Solved</title><link>http://0x3f.org/posts/project-euler-25-solved/</link><pubDate>Sat, 16 Aug 2014 17:32:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-25-solved/</guid><description>&lt;h2 id="1000-digit-fibonacci-number"&gt;1000-digit Fibonacci number&lt;/h2&gt;
&lt;p&gt;The Fibonacci sequence is defined by the recurrence relation:&lt;/p&gt;
&lt;p&gt;Fn = Fn−1 + Fn−2, where F1 = 1 and F2 = 1.&lt;/p&gt;
&lt;p&gt;Hence the first 12 terms will be:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;F1 = 1&lt;br&gt;
F2 = 1&lt;br&gt;
F3 = 2&lt;br&gt;
F4 = 3&lt;br&gt;
F5 = 5&lt;br&gt;
F6 = 8&lt;br&gt;
F7 = 13&lt;br&gt;
F8 = 21&lt;br&gt;
F9 = 34&lt;br&gt;
F10 = 55&lt;br&gt;
F11 = 89&lt;br&gt;
F12 = 144&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The 12th term, F12, is the first term to contain three digits.&lt;/p&gt;</description></item><item><title>读完《国史大纲》</title><link>http://0x3f.org/posts/after-reading-outline-history/</link><pubDate>Wed, 16 Jul 2014 21:27:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-outline-history/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DYBkUo68/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;钱穆先生主张以诚敬心审视国史和传统文化，一生为故国招魂。抗战流亡，笔耕不辍，虽然这本书只是一本历史教科书，但是高屋建瓴的大历史观让我受益匪浅，很多东西是读史料不能学到的。《国史大纲》所思所言，堪称国史良心。&lt;/p&gt;</description></item><item><title>使用 lsyncd 同步文件</title><link>http://0x3f.org/posts/live-syncing-daemon/</link><pubDate>Wed, 18 Jun 2014 14:03:00 +0000</pubDate><guid>http://0x3f.org/posts/live-syncing-daemon/</guid><description>&lt;p&gt;lsyncd全称“Live Syncing Daemon”，是Linux下的文件自动同步工具，同时支持SSH、rsync的实现方式。相对于rsync+inotify，它速度更快，也更稳定。&lt;/p&gt;
&lt;p&gt;对于SSH的方式，需要目标机器中已启动SSHD，并把源机器上的公钥加到目标机器root用户的authorized_keys中，私钥应放在源机器上运行lsyncd的用户的.ssh目录中，密钥放错了用户，会导致无法同步。&lt;/p&gt;
&lt;p&gt;然后就是在源机器上创建配置文件，lsyncd的配置文件是个lua脚本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pidfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/var/log/lsyncd/lsyncd.pid&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/var/log/lsyncd/lsyncd.log&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;statusFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/var/log/lsyncd/lsyncd-status.log&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;statusInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;maxDelays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;-- nodaemon = true,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;default.rsyncssh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/home/monk/workspace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;192.168.1.3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;targetdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/var/www/workspace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;*.tmp&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_extra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--bwlimit=50000&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后启动lsyncd：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lsyncd /etc/lsyncd.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Project Euler Problem 24 Solved</title><link>http://0x3f.org/posts/project-euler-24/</link><pubDate>Sun, 27 Apr 2014 21:17:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-24/</guid><description>&lt;h2 id="lexicographic-permutations"&gt;Lexicographic permutations&lt;/h2&gt;
&lt;p&gt;A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:&lt;/p&gt;
&lt;p&gt;012 021 102 120 201 210&lt;/p&gt;
&lt;p&gt;What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?&lt;/p&gt;</description></item><item><title>Project Euler Problem 23 Solved</title><link>http://0x3f.org/posts/project-euler-23/</link><pubDate>Fri, 25 Apr 2014 23:56:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-23/</guid><description>&lt;h2 id="non-abundant-sums"&gt;Non-abundant sums&lt;/h2&gt;
&lt;p&gt;A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.&lt;/p&gt;
&lt;p&gt;A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.&lt;/p&gt;</description></item><item><title>UltraBlog.vim v3.6.1: 文章分类自动补全</title><link>http://0x3f.org/posts/ultrablog-v361-released/</link><pubDate>Sun, 20 Apr 2014 22:50:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-v361-released/</guid><description>&lt;p&gt;春节期间收到两个issue，一直拖到今天才有时间完成。&lt;/p&gt;
&lt;p&gt;增加了一个功能，在文章编辑视图的元数据中分类那行，使用热键&amp;lt;C-X&amp;gt;&amp;lt;C-U&amp;gt;自动完成文章的分类。在配置数组&lt;strong&gt;ub_blog&lt;/strong&gt;中增加键值对“categories”，默认使用这一项的值实现自动完成，如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ub_blog&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; {&lt;span class="s1"&gt;&amp;#39;login_name&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; \&lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;pass2011&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; \&lt;span class="s1"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;http://www.sample.com/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; \&lt;span class="s1"&gt;&amp;#39;xmlrpc_uri&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;xmlrpc.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; \&lt;span class="s1"&gt;&amp;#39;db&amp;#39;&lt;/span&gt;:&lt;span class="s1"&gt;&amp;#39;$VIM/UltraBlog.db&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; \&lt;span class="s1"&gt;&amp;#39;categories&amp;#39;&lt;/span&gt;: &lt;span class="s1"&gt;&amp;#39;News|Computer|Image&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; \}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果这一项不存在，将从博客中拉取分类数据。&lt;/p&gt;
&lt;p&gt;自从迁移到Octopress，有两年不用Wordpress了，没想到居然还有人在用&lt;a href="http://0x3f.org/post/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>Project Euler Problem 22 Solved</title><link>http://0x3f.org/posts/project-euler-22/</link><pubDate>Sun, 20 Apr 2014 08:03:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-22/</guid><description>&lt;h2 id="names-scores"&gt;Names scores&lt;/h2&gt;
&lt;p&gt;Using &lt;a href="http://projecteuler.net/project/names.txt"&gt;names.txt&lt;/a&gt; (right click and &amp;lsquo;Save Link/Target As&amp;hellip;&amp;rsquo;), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.&lt;/p&gt;
&lt;p&gt;For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.&lt;/p&gt;</description></item><item><title>骑行的已知和未知</title><link>http://0x3f.org/posts/cycling-in-the-known-and-unknown/</link><pubDate>Sat, 19 Apr 2014 21:44:00 +0000</pubDate><guid>http://0x3f.org/posts/cycling-in-the-known-and-unknown/</guid><description>&lt;p&gt;暂时没有好路线，所以今天是保持性练习。上周发现顺时针绕道G109从军庄路放坡下来会很轻松，所以依旧从香岩寺出发，经黑山扈路、香山路、香山南路、八大处路、模式口大街、G109、军庄路、北清路，最后回到出发点。&lt;/p&gt;
&lt;p&gt;照例，先交作业：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DH6LbtQT/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DH6KVk28/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DH6KUt7T/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;走香山路是因为不想重复上周的老路，但是很快就体会到了不长记性的后果，这条路似乎从来没有不堵过，天气这么差都挡不住这么多人，植物园门口一坨一坨的，我一直觉得香山之难看、植物园之无聊可著北京城都是数一数二的，要不说文人可恶呢，忽悠了多少人！&lt;/p&gt;
&lt;p&gt;传说中的模式口大街居然只是一条很窄的巷子，两边是很旧的居民区，时近中午，这么窄的路上居然挤满了一坨一坨的人。&lt;/p&gt;
&lt;p&gt;军庄路似乎一般是上午会有很多拉土方的卡车，上周我中午过后经过时车就不多，不幸今天中奖了，要不是贪图放坡的快感，打死也不走这条路。&lt;/p&gt;
&lt;p&gt;总之今天走的不是个好路线，不如上周卢沟桥那一圈，很大程度上是因为想到的路线都有坡，加上天气不好、准备不充分，有点儿怵。以往的经历，第一次走的路线，因为不知道前面会有什么，怀著对未知的好奇和无畏，不管多困难，总是可以坚持下来，但下次就不敢了，因为有痛苦的经历。所以骑行的乐趣在于对未知的好奇，或者是克服对已知的恐惧。前一种我还行，至于后者，无力吐槽，唯余呵呵。&lt;/p&gt;</description></item><item><title>Project Euler Problem 21 Solved</title><link>http://0x3f.org/posts/project-euler-21/</link><pubDate>Thu, 17 Apr 2014 22:18:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-21/</guid><description>&lt;h2 id="amicable-numbers"&gt;Amicable numbers&lt;/h2&gt;
&lt;p&gt;Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).&lt;br&gt;
If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and each of a and b are called amicable numbers.&lt;/p&gt;
&lt;p&gt;For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.&lt;/p&gt;</description></item><item><title>Project Euler Problem 20 Solved</title><link>http://0x3f.org/posts/project-euler-20/</link><pubDate>Mon, 14 Apr 2014 22:19:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-20/</guid><description>&lt;h2 id="factorial-digit-sum"&gt;Factorial digit sum&lt;/h2&gt;
&lt;p&gt;n! means n × (n − 1) × &amp;hellip; × 3 × 2 × 1&lt;/p&gt;
&lt;p&gt;For example, 10! = 10 × 9 × &amp;hellip; × 3 × 2 × 1 = 3628800,&lt;br&gt;
and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.&lt;/p&gt;
&lt;p&gt;Find the sum of the digits in the number 100!&lt;/p&gt;</description></item><item><title>骑行卢沟桥</title><link>http://0x3f.org/posts/a-ride-to-lugou-bridge/</link><pubDate>Sun, 13 Apr 2014 19:55:00 +0000</pubDate><guid>http://0x3f.org/posts/a-ride-to-lugou-bridge/</guid><description>&lt;p&gt;更始元年三月癸丑，孤亲提铁骑南下卢沟，为甲午一百二十年祭。&lt;/p&gt;
&lt;p&gt;以前一直以为很远，后来发现单程只有三十多公里，而且基本都是平地，自从去年推上妙峰山后，一般难度就不怕不怕啦。&lt;/p&gt;
&lt;p&gt;先交作业：&lt;/p&gt;
&lt;p&gt;不知道为什么，记录到了北安河就结束了，最后十公里木有了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGaYw0Qi/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGaZP1XR/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGbqdTkZ/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;在网上见有人说从桥西进去不查门票，遂先过永定河，从西边进去，路上捡了个迷路的小盆友，说刚刚用手机导航直接上了高速！聊 后得知是北科大的学生，曾国藩的老乡，骑了辆不知道什么牌子的旧车，怯生生的，不禁遥想老夫当年，去矽谷吃顿七块钱的土豆牛肉饭都美得不行不行的。&lt;/p&gt;
&lt;p&gt;骑到桥西入口，一个大妈模样的头从售票处小窗口里伸出来：“二十！”，要不说我没有大妈缘呢，走到哪都被拦，去年苦逼哈哈地推到七王坟，大妈说封山防火，片板不得入山。老老实实地买了票，才见著真神，爱个国容易么。桥是金章宗的时候建的，乾隆五十多年重修。桥下就是永定河，左宗棠任直隶总督时在此治水，旧称无定河，不过不是“可怜无定河边骨，犹是春闺梦里人”里的那条。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGbmWZvZ/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;请小盆友拍了张孤王的戎装照：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGbmX91K/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;果然每个狮子都不一样，小学课本不余欺也：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGbmYClu/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;卢沟晓月，所谓的燕京八景之一，我一般不尿这种虚无缥缈、滥竽充数的东西，鲁迅在《再论雷峰塔的倒掉》里说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我们中国的许多人，——我在此特别正重声明：并不包括四万万同胞全部！——大抵患有一种“十景病”，至少是“八景病”，沉重起来的时候大概在清朝。凡看一部县志，这一县往往有十景或八景，如“远村明月”、“萧寺清钟”、“古池好水”之类。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我虽然不喜欢鲁迅，因为此人文风过于惼狭和左倾，虽然老先生一再声明不针对所有国人，但还是随处可见断章取义、不懂装懂的人扯大旗作虎皮，动辄就中国人的劣根性怎么怎么样。但在这一点上我跟老先生意见一致，就某些小县城都有所谓“七台八景”，台好歹还有个土堆，景就开始胡扯了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGbmY2fr/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;摆一堆仿明清的大炮干什么，跟七七世变不搭调，更容易联想到两甲子前的那场战争，此日漫挥天下泪，有公足庄海军威。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGcan9YW/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;小盆友的高中历史是体育老师教的，居然不知道宛平城。这座长宽只有几百米的小城是崇祯为抵御闯贼建的桥头堡。不要门票。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGbmXnSE/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这么小的一座城居然还有瓮城：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DGbmZQTg/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;城里有个抗日纪念馆，免费参观，因为没处存车，没有进去，不过受党国栽培多年，用脚趾头也能想到里面都是什么，不去也罢。城里没啥可吃的，小盆友说要回校再吃饭，我心说您是直接奔学院路了，我还有几十公里路要绕，不补充热量怎么行，请小盆友吃了顿热干面。这兄弟明显没有方向感，好容易才让他找著北，在手机上找好回学院路的路线，最后送出东门，然后告诉他怎么走之后，老夫才起驾回宫。&lt;/p&gt;
&lt;p&gt;之后的路基本比较轻松，大体沿永定河一直走，河边的永定楼气势恢宏，懒得拍照了，再上G109，从军庄路一路放坡下来，很爽。&lt;/p&gt;</description></item><item><title>Project Euler Problem 19 Solved</title><link>http://0x3f.org/posts/project-euler-19/</link><pubDate>Sat, 12 Apr 2014 21:21:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-19/</guid><description>&lt;h2 id="counting-sundays"&gt;Counting Sundays&lt;/h2&gt;
&lt;p&gt;You are given the following information, but you may prefer to do some research for yourself.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 Jan 1900 was a Monday.&lt;/li&gt;
&lt;li&gt;Thirty days has September,
April, June and November.&lt;br&gt;
All the rest have thirty-one,&lt;br&gt;
Saving February alone,&lt;br&gt;
Which has twenty-eight, rain or shine.&lt;br&gt;
And on leap years, twenty-nine.&lt;/li&gt;
&lt;li&gt;A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?&lt;/p&gt;</description></item><item><title>Project Euler Problem 18&amp;67 Solved</title><link>http://0x3f.org/posts/project-euler-18-and-67/</link><pubDate>Thu, 10 Apr 2014 21:28:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-18-and-67/</guid><description>&lt;h2 id="maximum-path-sum-i"&gt;Maximum path sum I&lt;/h2&gt;
&lt;p&gt;By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.&lt;/p&gt;
&lt;p&gt;3&lt;br&gt;
7 4&lt;br&gt;
2 4 6&lt;br&gt;
8 5 9 3&lt;/p&gt;
&lt;p&gt;That is, 3 + 7 + 4 + 9 = 23.&lt;/p&gt;
&lt;p&gt;Find the maximum total from top to bottom of the triangle below:&lt;/p&gt;
&lt;p&gt;75&lt;br&gt;
95 64&lt;br&gt;
17 47 82&lt;br&gt;
18 35 87 10&lt;br&gt;
20 04 82 47 65&lt;br&gt;
19 01 23 75 03 34&lt;br&gt;
88 02 77 73 07 63 67&lt;br&gt;
99 65 04 28 06 16 70 92&lt;br&gt;
41 41 26 56 83 40 80 70 33&lt;br&gt;
41 48 72 33 47 32 37 16 94 29&lt;br&gt;
53 71 44 65 25 43 91 52 97 51 14&lt;br&gt;
70 11 33 28 77 73 17 78 39 68 17 57&lt;br&gt;
91 71 52 38 17 14 91 43 58 50 27 29 48&lt;br&gt;
63 66 04 68 89 53 67 30 73 16 69 87 40 31&lt;br&gt;
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23&lt;/p&gt;</description></item><item><title>Project Euler Problem 17 Solved</title><link>http://0x3f.org/posts/project-euler-17/</link><pubDate>Wed, 09 Apr 2014 22:29:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-17/</guid><description>&lt;h2 id="number-letter-counts"&gt;Number letter counts&lt;/h2&gt;
&lt;p&gt;If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.&lt;/p&gt;
&lt;p&gt;If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of &amp;ldquo;and&amp;rdquo; when writing out numbers is in compliance with British usage.&lt;/p&gt;</description></item><item><title>Project Euler Problem 16 Solved</title><link>http://0x3f.org/posts/project-euler-16/</link><pubDate>Tue, 08 Apr 2014 21:57:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-16/</guid><description>&lt;h2 id="power-digit-sum"&gt;Power digit sum&lt;/h2&gt;
&lt;p&gt;2^15 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.&lt;/p&gt;
&lt;p&gt;What is the sum of the digits of the number 2^1000?&lt;/p&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ch"&gt;#!/usr/bin/python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;f&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;math/big&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;big&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;big&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;power&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;power&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;power&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bit&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m the 109044th person to have solved this problem.&lt;/p&gt;</description></item><item><title>Project Euler Problem 15 Solved</title><link>http://0x3f.org/posts/project-euler-15/</link><pubDate>Wed, 02 Apr 2014 21:44:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-15/</guid><description>&lt;h2 id="lattice-paths"&gt;Lattice paths&lt;/h2&gt;
&lt;p&gt;Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DEwoQ7qc/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;How many such routes are there through a 20×20 grid?&lt;/p&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ch"&gt;#!/usr/bin/python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m the 86747th person to have solved this problem.&lt;/p&gt;</description></item><item><title>Project Euler Problem 14 Solved</title><link>http://0x3f.org/posts/project-euler-14/</link><pubDate>Tue, 01 Apr 2014 22:17:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-14/</guid><description>&lt;h2 id="longest-collatz-sequence"&gt;Longest Collatz sequence&lt;/h2&gt;
&lt;p&gt;The following iterative sequence is defined for the set of positive integers:&lt;/p&gt;
&lt;p&gt;n → n/2 (n is even)&lt;br&gt;
n → 3n + 1 (n is odd)&lt;/p&gt;
&lt;p&gt;Using the rule above and starting with 13, we generate the following sequence:&lt;/p&gt;
&lt;p&gt;13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1&lt;/p&gt;
&lt;p&gt;It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.&lt;/p&gt;</description></item><item><title>PHP框架实战（六）：依赖注入</title><link>http://0x3f.org/posts/flamework-dependency-injection/</link><pubDate>Sun, 30 Mar 2014 10:00:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-dependency-injection/</guid><description>&lt;h2 id="简述"&gt;简述&lt;/h2&gt;
&lt;p&gt;依赖注入是个很好的解耦方法，也可以优雅的实现懒加载。&lt;/p&gt;
&lt;p&gt;以数据库连接为例，当一个组件用到数据库时，最简单粗暴的办法是在使用前创建连接：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doSth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这样做的缺点是代码一旦执行，Component行为将不可更改，有时我们需要在程序执行的过程中决定其行为。很直接地，可以想到给Component添加一个Setter方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$__db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doSth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;__db&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// do something ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;__db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这样就把Component和数据库连接解耦了。这时又有一个问题，怎样管理数据库连接？最简单粗暴的办法是在每次使用前创建，如果在程序中多处需要改变数据库连接，这就把代码写死了。&lt;/p&gt;</description></item><item><title>Project Euler Problem 13 Solved</title><link>http://0x3f.org/posts/project-euler-13/</link><pubDate>Sun, 30 Mar 2014 09:50:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-13/</guid><description>&lt;h2 id="large-sum"&gt;Large sum&lt;/h2&gt;
&lt;p&gt;Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.&lt;/p&gt;
&lt;p&gt;37107287533902102798797998220837590246510135740250
46376937677490009712648124896970078050417018260538
74324986199524741059474233309513058123726617309629
91942213363574161572522430563301811072406154908250
23067588207539346171171980310421047513778063246676
89261670696623633820136378418383684178734361726757
28112879812849979408065481931592621691275889832738
44274228917432520321923589422876796487670272189318
47451445736001306439091167216856844588711603153276
70386486105843025439939619828917593665686757934951
62176457141856560629502157223196586755079324193331
64906352462741904929101432445813822663347944758178
92575867718337217661963751590579239728245598838407
58203565325359399008402633568948830189458628227828
80181199384826282014278194139940567587151170094390
35398664372827112653829987240784473053190104293586
86515506006295864861532075273371959191420517255829
71693888707715466499115593487603532921714970056938
54370070576826684624621495650076471787294438377604
53282654108756828443191190634694037855217779295145
36123272525000296071075082563815656710885258350721
45876576172410976447339110607218265236877223636045
17423706905851860660448207621209813287860733969412
81142660418086830619328460811191061556940512689692
51934325451728388641918047049293215058642563049483
62467221648435076201727918039944693004732956340691
15732444386908125794514089057706229429197107928209
55037687525678773091862540744969844508330393682126
18336384825330154686196124348767681297534375946515
80386287592878490201521685554828717201219257766954
78182833757993103614740356856449095527097864797581
16726320100436897842553539920931837441497806860984
48403098129077791799088218795327364475675590848030
87086987551392711854517078544161852424320693150332
59959406895756536782107074926966537676326235447210
69793950679652694742597709739166693763042633987085
41052684708299085211399427365734116182760315001271
65378607361501080857009149939512557028198746004375
35829035317434717326932123578154982629742552737307
94953759765105305946966067683156574377167401875275
88902802571733229619176668713819931811048770190271
25267680276078003013678680992525463401061632866526
36270218540497705585629946580636237993140746255962
24074486908231174977792365466257246923322810917141
91430288197103288597806669760892938638285025333403
34413065578016127815921815005561868836468420090470
23053081172816430487623791969842487255036638784583
11487696932154902810424020138335124462181441773470
63783299490636259666498587618221225225512486764533
67720186971698544312419572409913959008952310058822
95548255300263520781532296796249481641953868218774
76085327132285723110424803456124867697064507995236
37774242535411291684276865538926205024910326572967
23701913275725675285653248258265463092207058596522
29798860272258331913126375147341994889534765745501
18495701454879288984856827726077713721403798879715
38298203783031473527721580348144513491373226651381
34829543829199918180278916522431027392251122869539
40957953066405232632538044100059654939159879593635
29746152185502371307642255121183693803580388584903
41698116222072977186158236678424689157993532961922
62467957194401269043877107275048102390895523597457
23189706772547915061505504953922979530901129967519
86188088225875314529584099251203829009407770775672
11306739708304724483816533873502340845647058077308
82959174767140363198008187129011875491310547126581
97623331044818386269515456334926366572897563400500
42846280183517070527831839425882145521227251250327
55121603546981200581762165212827652751691296897789
32238195734329339946437501907836945765883352399886
75506164965184775180738168837861091527357929701337
62177842752192623401942399639168044983993173312731
32924185707147349566916674687634660915035914677504
99518671430235219628894890102423325116913619626622
73267460800591547471830798392868535206946944540724
76841822524674417161514036427982273348055556214818
97142617910342598647204516893989422179826088076852
87783646182799346313767754307809363333018982642090
10848802521674670883215120185883543223812876952786
71329612474782464538636993009049310363619763878039
62184073572399794223406235393808339651327408011116
66627891981488087797941876876144230030984490851411
60661826293682836764744779239180335110989069790714
85786944089552990653640447425576083659976645795096
66024396409905389607120198219976047599490197230297
64913982680032973156037120041377903785566085089252
16730939319872750275468906903707539413042652315011
94809377245048795150954100921645863754710598436791
78639167021187492431995700641917969777599028300699
15368713711936614952811305876380278410754449733078
40789923115535562561142322423255033685442488917353
44889911501440648020369068063960672322193204149535
41503128880339536053299340368006977710650566631954
81234880673210146739058568557934581403627822703280
82616570773948327592232845941706525094512325230608
22918802058777319719839450180888072429661980811197
77158542502016545090413245809786882778948721859617
72107838435069186155435662884062257473692284509516
20849603980134001723930671666823555245252804609722
53503534226472524250874054075591789781264330331690&lt;/p&gt;</description></item><item><title>二骑白羊沟</title><link>http://0x3f.org/posts/2nd-ride-to-white-goat-valley/</link><pubDate>Sat, 29 Mar 2014 20:16:00 +0000</pubDate><guid>http://0x3f.org/posts/2nd-ride-to-white-goat-valley/</guid><description>&lt;p&gt;桃花、迎春花开得很好，但没有秋天长满路边的花有气氛。早上去得晚了，阳坊镇的小笼包收摊了……&lt;/p&gt;
&lt;p&gt;交作业：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DDU0q8d7/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DDU0sey9/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DDU0s9ak/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这次一口气上了魔鬼六连弯，弯口溪水别样清啊：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DDU0s3cm/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;小蓝月湖，命名权是我的：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DDU2DREG/medish.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Project Euler Problem 12 Solved</title><link>http://0x3f.org/posts/project-euler-12/</link><pubDate>Fri, 28 Mar 2014 22:51:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-12/</guid><description>&lt;h2 id="highly-divisible-triangular-number"&gt;Highly divisible triangular number&lt;/h2&gt;
&lt;p&gt;The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:&lt;/p&gt;
&lt;p&gt;1, 3, 6, 10, 15, 21, 28, 36, 45, 55, &amp;hellip;&lt;/p&gt;
&lt;p&gt;Let us list the factors of the first seven triangle numbers:&lt;/p&gt;
&lt;p&gt;1: 1&lt;br&gt;
3: 1,3&lt;br&gt;
6: 1,2,3,6&lt;br&gt;
10: 1,2,5,10&lt;br&gt;
15: 1,3,5,15&lt;br&gt;
21: 1,3,7,21&lt;br&gt;
28: 1,2,4,7,14,28&lt;/p&gt;</description></item><item><title>使用存取控制表在Linux用户间共享文件</title><link>http://0x3f.org/posts/share-file-using-access-control-lists/</link><pubDate>Wed, 19 Mar 2014 22:38:00 +0000</pubDate><guid>http://0x3f.org/posts/share-file-using-access-control-lists/</guid><description>&lt;p&gt;我用Dropbox在两台电脑间同步个人维基数据，将数据目录从Web Server下软连接到Dropbox里，而对Dropbox目录的备份实际上只包含那个软连接，没有内容，结果当把备份拷贝到另一台电脑上并打开Dropbox后，维基数据被清空了！我积累多年的笔记差一点儿完蛋，幸亏单独备份过维基。然后改将维基数据放到Dropbox里，然后软连接到Web Server下，新问题出现了，Web Server是以http身份运行的，对用户主目录没有权限，当然也不能访问主目录下的Dropbox目录。&lt;/p&gt;
&lt;p&gt;最简单的办法是将主目录、Dropbox、维基目录的权限全部设成777，显然，这样做太不安全。另一种方法是把Dropbox用NFS输出，然后挂载到Web Server下，这么做太蛋疼。最合适的解决方案是Access Control List（存取控制表），它可以为文件和目录设置具体到单个用户或用户组的存取权限，实现像Windows下的文件（目录）共享权限设置那样的效果，而且比后者更强大、灵活。&lt;/p&gt;
&lt;p&gt;使用ACL首先需要目录的挂载选项中包含acl，不过一般缺省都包含这一项。&lt;/p&gt;
&lt;p&gt;ACL包含两个命令：getfacl和setfacl，前者用来查看目录或文件的存取控制表，后者用来操作它。&lt;/p&gt;
&lt;p&gt;首先，把维基目录的所有者改成http，并设置目录权限为770：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chown -R http:http ~/Dropbox/wiki
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod -R &lt;span class="m"&gt;770&lt;/span&gt; ~/Dropbox/wiki
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这时Web Server还是不能访问维基目录，使用getfacl查看用户主目录的ACL：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getfacl ~
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;显示结果如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;getfacl: Removing leading &amp;lsquo;/&amp;rsquo; from absolute path names&lt;br&gt;
# file: home/taoqi&lt;br&gt;
# owner: taoqi&lt;br&gt;
# group: users&lt;br&gt;
user::rwx&lt;br&gt;
user:root:&amp;ndash;x&lt;br&gt;
group::&amp;mdash;&lt;br&gt;
mask::&amp;ndash;x&lt;br&gt;
other::&amp;mdash;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;显然，要给http用户访问该目录的权限：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;setfacl -m u:http:x ~
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;再查看ACL，发现增加了一条：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;user:http:&amp;ndash;x&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;同理，给Dropbox目录也加上这一条规则之后，Web Server就可以访问维基数据目录了。&lt;/p&gt;</description></item><item><title>西山徒步——大觉寺至凤凰岭南线</title><link>http://0x3f.org/posts/a-walk-through-the-west-mountain/</link><pubDate>Sat, 15 Mar 2014 19:56:00 +0000</pubDate><guid>http://0x3f.org/posts/a-walk-through-the-west-mountain/</guid><description>&lt;p&gt;从大觉寺上，至凤凰岭南线下，全程十六公里，最高海拔一千多米，上升一千米，用时七个多小时，难度适中。全程用行者骑行软件记录，挺好用，GPS定位准，耗电不大，魅族MX3大概用了60%的电。&lt;/p&gt;
&lt;p&gt;记录数据：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBVrawlL/medish.jpg" alt=""&gt;
&lt;img src="http://pic.yupoo.com/leninlee/DBVraDFN/medish.jpg" alt=""&gt;
&lt;img src="http://pic.yupoo.com/leninlee/DBVqWKLy/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;山上的公路很好，在这里骑行挺好的，只是不知道从哪上来：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBVrlHDT/medish.jpg" alt=""&gt;
&lt;img src="http://pic.yupoo.com/leninlee/DBVr8MUb/medish.jpg" alt=""&gt;
&lt;img src="http://pic.yupoo.com/leninlee/DBVr9DBD/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;在山上接了壶泉水，陆羽《茶经·煮》里说：“其水，用山水上，江水中，井水下”，上水烹茶，不言其中：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBVrbnSf/medish.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>读完《The C Programming Language》</title><link>http://0x3f.org/posts/after-reading-the-c-programming-language/</link><pubDate>Sun, 09 Mar 2014 22:47:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-the-c-programming-language/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DASqD5IQ/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;谭书可能因为面向学生而显得啰嗦，这本书比谭书精炼。&lt;/p&gt;</description></item><item><title>探访纳兰家庙</title><link>http://0x3f.org/posts/a-visit-to-the-family-temple-of-nalans/</link><pubDate>Fri, 07 Mar 2014 18:25:00 +0000</pubDate><guid>http://0x3f.org/posts/a-visit-to-the-family-temple-of-nalans/</guid><description>&lt;p&gt;客居多年，不久前才知道附近有如此底蕴的一个去处，于是赶在开始一段新行程前探访了这里。&lt;/p&gt;
&lt;p&gt;永泰庄东岳庙，始建于明代，经清代纳兰明珠遗言修缮，供奉明珠牌位，所以又叫纳兰家庙，据说纳兰性德也葬在附近，不过已经难觅词踪。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBUVKtAr/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBUVLKQF/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;前殿已经残破不堪，横生凄凉：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBUVMdTB/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;钟鼓楼已经只剩下西面一座：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBUWy7Xf/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBUVOlJB/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;虽然没有重簷，正殿仍然显得很有气势：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBUVPpcm/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DBUVQinI/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;宋以后中国知识界思想僵化，明清两代能拿得出手的只有小品和小说，纳兰词是一个异数，有清一代的诗词里，一定少不了那句“人生若只如初见”。&lt;/p&gt;</description></item><item><title>读完《你一定爱读的极简欧洲史》</title><link>http://0x3f.org/posts/after-reading-the-shortest-history-of-europe/</link><pubDate>Sun, 23 Feb 2014 20:57:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-the-shortest-history-of-europe/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DyJGJDhw/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;中国的历史教育培养了一群读了二十年书还分不清五胡十六国和五代十国的人，看看人家是怎么教历史的，提纲挈领比死记签了哪些条约有用多了。&lt;/p&gt;</description></item><item><title>读完《大数据时代》</title><link>http://0x3f.org/posts/after-reading-big-data-era/</link><pubDate>Sat, 08 Feb 2014 10:11:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-big-data-era/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DwnY4bqO/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;读完，我首先感到的不是大数据有多可爱，而是有多可怕。&lt;/p&gt;</description></item><item><title>读完《万历十五年》</title><link>http://0x3f.org/posts/after-reading-a-year-of-no-significance/</link><pubDate>Mon, 03 Feb 2014 13:17:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-a-year-of-no-significance/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DvE1PYrK/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;国史奇书，一本书读懂三百年大明。&lt;/p&gt;</description></item><item><title>读完《Go Web编程》</title><link>http://0x3f.org/posts/after-reading-build-web-application-with-golang/</link><pubDate>Sun, 02 Feb 2014 15:52:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-build-web-application-with-golang/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DvvA9fkE/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;用较少的篇幅介绍了golang的语法，然后从实现的角度讲了一些Web应用的概念，最后介绍了beego框架。程序员思维，很实用，讲Web应用基础概念的实现的部分很有用，这方面的书不多。语言表达和示例代码有提升的空间。是Go语言很好的入门教材。&lt;/p&gt;</description></item><item><title>读完《明朝那些事儿》</title><link>http://0x3f.org/posts/after-reading-ming-chao-na-xie-shi/</link><pubDate>Wed, 29 Jan 2014 12:14:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-ming-chao-na-xie-shi/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DuSsCV8B/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;还旧账，多年前读的时候这本书还没有写完，趁读完《通鉴》把最后两本解决了。下面计划读的是《万历十五年》，今年是我的明矾年么？&lt;/p&gt;</description></item><item><title>读完《资治通鉴》</title><link>http://0x3f.org/posts/after-reading-tong-jian/</link><pubDate>Tue, 28 Jan 2014 20:53:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-tong-jian/</guid><description>&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DuMqtc1v/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;一部书，二百九十四卷，三百万字，一千三百六十二年，从中华书局20册胡三省注本，到Kindle DXG，再到Kindle Paperwhite，读了四年。&lt;/p&gt;
&lt;p&gt;读史应该先读通史，再读断代史，然后是野史。因为读懂历史必须站在大时代背景上，比如不了解两周封建拓殖史，就不懂什么是“南夷与北狄交，中国不绝若线。”，更不会明白“尊王攘夷”区区四个字有多大的份量。所以十年前我《世说新语》刚读了个开头就读不下去了。&lt;/p&gt;
&lt;p&gt;《通鉴》关注的是兴衰更替，所以很多有意思的历史故事没有记录，尤其是先秦时期，我最喜欢的传奇时代，结果看得索然无味。汉纪部分又包含了太多的上书和诏书。我一度觉得选择读《通鉴》是个错误。&lt;/p&gt;
&lt;p&gt;所幸坚持了下来，鉴于自小说作家司马迁开始，我国历代史家保持著添油加醋的优良传统，越生动的历史往往越不可信，去叶存枝方见国史之骨。如果说两司马有什么区别，前者是用故事讲历史，后者是用历史讲历史，单就史学而言，谁更牛X，一目了然。&lt;/p&gt;</description></item><item><title>PHP框架实战（∝）：烈焰之终章</title><link>http://0x3f.org/posts/flamework-summary/</link><pubDate>Thu, 02 Jan 2014 15:15:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-summary/</guid><description>&lt;p&gt;写“烈焰”（Flame）用了一周的业余时间，主要是对平时一些想法的总结和验证。实现了比较完整的控制器层和视图层，对模型层的ActiveRecord实现思路做了一下梳理。&lt;/p&gt;
&lt;p&gt;当然，一个可实用的框架需要包含的东西远不止这些。比如框架中用到代码动态调用的地方，一定要做好语言安全子集的过滤，否则就是很大的安全漏洞。再比如需要支持依赖反转的缓存机制，实现对多种缓存方式的平滑支持。此外，像URI路由、可扩展、多模板方案支持也都是现代框架的标配。这些留待以后有时间再讨论。然而在这次练习的过程中，我突然想到一个问题——PHP是不是适合实现一个完备的框架。&lt;/p&gt;
&lt;p&gt;曾见过一句话，说PHP本身就是一个框架，后来明白，这才是微言大义。PHP有很多高级选项、高级函数和扩展，用得好事半功倍，用不好就是魔鬼。&lt;/p&gt;
&lt;p&gt;PHP本身有很多问题，协议不统一、函数命名混乱、命名空间语法怪异而且鸡肋等等都是老生常谈。在运行模式上，无论是Apache+PHP模块，还是NGINX+FastCGI，都只能实现在纵向层面上对一次请求的处理，由于缺乏在内存中持续运行程序的机制，凡是对程序全局共享并持续占有的东西都不能实现，比如数据库连接池等，以至于很多初始化的工作对于每次请求都要重新执行一次，这意味著面向对象越彻底、封装越多，系统资源的重复消耗越厉害，所以PHP的程序在性能和内存占用上与Java相比有一定缺陷。因此PHP更适合短平快的应用场景，不适合实现复杂的业务逻辑。&lt;/p&gt;
&lt;p&gt;基于这个观点，我认同混合编程。没有哪种语言是完美的，用对的工具做对的事是最理想的。用PHP实现一个完备的框架也许不是个明智的选择，从短平快的角度出发，它更适合用来实现微框架。&lt;/p&gt;
&lt;p&gt;现在微框架是个比较热门的话题，我最早接触的是Python的Bottle和Flask，短小精悍，非常容易上手。微框架主要实现控制器层和视图层，一般不包括模型层。为了以最快的速度将请求路由到处理逻辑，一般以最直接的方式建立URI模板和回调物件之间的映射，控制器层可以以极简的方式实现，例如只做一个像本文后面例子中那样简单的约定。微框架应该尽可能少地包含配置，大部分时候并不需要像Java的S.S.H那样滥用配置，&lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;CoC原则&lt;/a&gt;就持这样的观点，约定可以解决的问题就不要用配置去做。&lt;/p&gt;
&lt;p&gt;下面只使用两个函数和五条约定实现一个微框架：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 路由定义与应用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $route 用作定义路由规则时，此参数为模板字符串，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 使用冒号加参数名作为参数占位符，例如：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * on(&amp;#39;/post/edit/:id&amp;#39;, function($id){});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 用做应用路由规则时，此参数为URI，例如：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * on($_SERVER[&amp;#39;REQUEST_URI&amp;#39;]);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param callable $callback 路由规则的回调逻辑，如果路由规则中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 含有参数占位符，回调中需存在同名的参数；当函数作为应用路
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 由规则使用时，此参数不指定
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nv"&gt;$routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#:[^\/]+#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.*&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$route&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$routes&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$r&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$cfg&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$route&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;strpos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;$keys&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array_combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call_user_func_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;404&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * 视图渲染函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $view 视图名称
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param array $params 关联数组，包含需要填到视图模板中的参数键值对
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EXTR_PREFIX_SAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tpl_&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$viewFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;realpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;view&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is_readable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$viewFile&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$viewFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;View template &lt;/span&gt;&lt;span class="si"&gt;$view&lt;/span&gt;&lt;span class="s2"&gt; does not exist or cannot be readable.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;on()身兼两用，一是定义路由规则和对应的响应逻辑，一是对指定URI应用路由规则。render()的作用是渲染视图模板。用法如下：&lt;/p&gt;</description></item><item><title>PHP框架实战（五）：ORM与ActiveRecord</title><link>http://0x3f.org/posts/flamework-active-record/</link><pubDate>Wed, 01 Jan 2014 20:45:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-active-record/</guid><description>&lt;h2 id="简述"&gt;简述&lt;/h2&gt;
&lt;p&gt;Model是MVC框架中最复杂的部分，它要提供与业务逻辑相关的数据及数据处理方法的封装，一般要提供数据对象、数据库连接、事务管理、SQL语句构造、数据CRUD、高级通用业务逻辑等一系列功能。由于Model与Controller和View是解耦的，并且本身具备很高的通用性和复杂性，所以有很多独立的实现。本文希望能通过开发一个简单的ActiveRecord，验证这种Model实现方案的原理和过程。&lt;/p&gt;
&lt;h2 id="orm对象关系映射"&gt;ORM：对象关系映射&lt;/h2&gt;
&lt;p&gt;ORM的全称是Object Relational Mapping，即对象关系映射。它是为了解决关系数据库的数学模型和编程语言的对象模型之间的阻抗不匹配问题而提出的解决方案。&lt;/p&gt;
&lt;p&gt;阻抗不匹配是个逼格很高的词。&lt;/p&gt;
&lt;p&gt;阻抗是指电路中的电容、电感、电阻对交流电的障碍作用，就像电阻对直流电的障碍作用。两个系统传递信号可以形象地看成电压的传递，公式为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;                &lt;strong&gt;U&lt;/strong&gt;(out) * &lt;strong&gt;Z&lt;/strong&gt;(in)&lt;br&gt;
&lt;strong&gt;U&lt;/strong&gt;(in) = &amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;&lt;br&gt;
                &lt;strong&gt;Z&lt;/strong&gt;(in) + &lt;strong&gt;Z&lt;/strong&gt;(out)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;即输入电压等于输出电压与输入阻抗的积除以输入阻抗与输出阻抗的和。&lt;/p&gt;
&lt;p&gt;理想情况肯定是输入电压等于输出电压，这时信号是没有失真的，也就是要求Z(in)与Z(in)+Z(out)之商无限逼近1，这个过程就叫阻抗匹配。关系型数据库是建立在数学模型的基础上，而编程语言中的对象是建立在人对客观世界认知的具象模型上。说白了，阻抗不匹配问题就是说因这两种模型不一致而导致的问题。&lt;/p&gt;
&lt;p&gt;ORM通过建立表与对象、列与属性（&lt;em&gt;这只是一般情况&lt;/em&gt;）之间的映射关系而解决问题，这可以实现像操作对象一样对数据库中的数据进行增删改查，简化了开发过程。不过ORM的缺点是不能很好地处理复杂数据关系，会出现效率低下的问题，因此必要时仍然需要直接使用SQL。&lt;/p&gt;
&lt;h2 id="activerecord"&gt;ActiveRecord&lt;/h2&gt;
&lt;p&gt;ActiveRecord是Ruby on Rails提出的一个概念，其实就是ORM的一种实现，它是对象类型、数据、CRUD方法的合体，使对数据的操作以更具象化的方式实现。下面介绍在Flamework中实现一个简单的ActiveRecord的过程。&lt;/p&gt;
&lt;p&gt;首先实现数据库的接口，提供数据库连接、查询、执行SQL语句、事务管理等基本功能。这里使用PDO实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt; 10
&lt;/span&gt;&lt;span class="lnt"&gt; 11
&lt;/span&gt;&lt;span class="lnt"&gt; 12
&lt;/span&gt;&lt;span class="lnt"&gt; 13
&lt;/span&gt;&lt;span class="lnt"&gt; 14
&lt;/span&gt;&lt;span class="lnt"&gt; 15
&lt;/span&gt;&lt;span class="lnt"&gt; 16
&lt;/span&gt;&lt;span class="lnt"&gt; 17
&lt;/span&gt;&lt;span class="lnt"&gt; 18
&lt;/span&gt;&lt;span class="lnt"&gt; 19
&lt;/span&gt;&lt;span class="lnt"&gt; 20
&lt;/span&gt;&lt;span class="lnt"&gt; 21
&lt;/span&gt;&lt;span class="lnt"&gt; 22
&lt;/span&gt;&lt;span class="lnt"&gt; 23
&lt;/span&gt;&lt;span class="lnt"&gt; 24
&lt;/span&gt;&lt;span class="lnt"&gt; 25
&lt;/span&gt;&lt;span class="lnt"&gt; 26
&lt;/span&gt;&lt;span class="lnt"&gt; 27
&lt;/span&gt;&lt;span class="lnt"&gt; 28
&lt;/span&gt;&lt;span class="lnt"&gt; 29
&lt;/span&gt;&lt;span class="lnt"&gt; 30
&lt;/span&gt;&lt;span class="lnt"&gt; 31
&lt;/span&gt;&lt;span class="lnt"&gt; 32
&lt;/span&gt;&lt;span class="lnt"&gt; 33
&lt;/span&gt;&lt;span class="lnt"&gt; 34
&lt;/span&gt;&lt;span class="lnt"&gt; 35
&lt;/span&gt;&lt;span class="lnt"&gt; 36
&lt;/span&gt;&lt;span class="lnt"&gt; 37
&lt;/span&gt;&lt;span class="lnt"&gt; 38
&lt;/span&gt;&lt;span class="lnt"&gt; 39
&lt;/span&gt;&lt;span class="lnt"&gt; 40
&lt;/span&gt;&lt;span class="lnt"&gt; 41
&lt;/span&gt;&lt;span class="lnt"&gt; 42
&lt;/span&gt;&lt;span class="lnt"&gt; 43
&lt;/span&gt;&lt;span class="lnt"&gt; 44
&lt;/span&gt;&lt;span class="lnt"&gt; 45
&lt;/span&gt;&lt;span class="lnt"&gt; 46
&lt;/span&gt;&lt;span class="lnt"&gt; 47
&lt;/span&gt;&lt;span class="lnt"&gt; 48
&lt;/span&gt;&lt;span class="lnt"&gt; 49
&lt;/span&gt;&lt;span class="lnt"&gt; 50
&lt;/span&gt;&lt;span class="lnt"&gt; 51
&lt;/span&gt;&lt;span class="lnt"&gt; 52
&lt;/span&gt;&lt;span class="lnt"&gt; 53
&lt;/span&gt;&lt;span class="lnt"&gt; 54
&lt;/span&gt;&lt;span class="lnt"&gt; 55
&lt;/span&gt;&lt;span class="lnt"&gt; 56
&lt;/span&gt;&lt;span class="lnt"&gt; 57
&lt;/span&gt;&lt;span class="lnt"&gt; 58
&lt;/span&gt;&lt;span class="lnt"&gt; 59
&lt;/span&gt;&lt;span class="lnt"&gt; 60
&lt;/span&gt;&lt;span class="lnt"&gt; 61
&lt;/span&gt;&lt;span class="lnt"&gt; 62
&lt;/span&gt;&lt;span class="lnt"&gt; 63
&lt;/span&gt;&lt;span class="lnt"&gt; 64
&lt;/span&gt;&lt;span class="lnt"&gt; 65
&lt;/span&gt;&lt;span class="lnt"&gt; 66
&lt;/span&gt;&lt;span class="lnt"&gt; 67
&lt;/span&gt;&lt;span class="lnt"&gt; 68
&lt;/span&gt;&lt;span class="lnt"&gt; 69
&lt;/span&gt;&lt;span class="lnt"&gt; 70
&lt;/span&gt;&lt;span class="lnt"&gt; 71
&lt;/span&gt;&lt;span class="lnt"&gt; 72
&lt;/span&gt;&lt;span class="lnt"&gt; 73
&lt;/span&gt;&lt;span class="lnt"&gt; 74
&lt;/span&gt;&lt;span class="lnt"&gt; 75
&lt;/span&gt;&lt;span class="lnt"&gt; 76
&lt;/span&gt;&lt;span class="lnt"&gt; 77
&lt;/span&gt;&lt;span class="lnt"&gt; 78
&lt;/span&gt;&lt;span class="lnt"&gt; 79
&lt;/span&gt;&lt;span class="lnt"&gt; 80
&lt;/span&gt;&lt;span class="lnt"&gt; 81
&lt;/span&gt;&lt;span class="lnt"&gt; 82
&lt;/span&gt;&lt;span class="lnt"&gt; 83
&lt;/span&gt;&lt;span class="lnt"&gt; 84
&lt;/span&gt;&lt;span class="lnt"&gt; 85
&lt;/span&gt;&lt;span class="lnt"&gt; 86
&lt;/span&gt;&lt;span class="lnt"&gt; 87
&lt;/span&gt;&lt;span class="lnt"&gt; 88
&lt;/span&gt;&lt;span class="lnt"&gt; 89
&lt;/span&gt;&lt;span class="lnt"&gt; 90
&lt;/span&gt;&lt;span class="lnt"&gt; 91
&lt;/span&gt;&lt;span class="lnt"&gt; 92
&lt;/span&gt;&lt;span class="lnt"&gt; 93
&lt;/span&gt;&lt;span class="lnt"&gt; 94
&lt;/span&gt;&lt;span class="lnt"&gt; 95
&lt;/span&gt;&lt;span class="lnt"&gt; 96
&lt;/span&gt;&lt;span class="lnt"&gt; 97
&lt;/span&gt;&lt;span class="lnt"&gt; 98
&lt;/span&gt;&lt;span class="lnt"&gt; 99
&lt;/span&gt;&lt;span class="lnt"&gt;100
&lt;/span&gt;&lt;span class="lnt"&gt;101
&lt;/span&gt;&lt;span class="lnt"&gt;102
&lt;/span&gt;&lt;span class="lnt"&gt;103
&lt;/span&gt;&lt;span class="lnt"&gt;104
&lt;/span&gt;&lt;span class="lnt"&gt;105
&lt;/span&gt;&lt;span class="lnt"&gt;106
&lt;/span&gt;&lt;span class="lnt"&gt;107
&lt;/span&gt;&lt;span class="lnt"&gt;108
&lt;/span&gt;&lt;span class="lnt"&gt;109
&lt;/span&gt;&lt;span class="lnt"&gt;110
&lt;/span&gt;&lt;span class="lnt"&gt;111
&lt;/span&gt;&lt;span class="lnt"&gt;112
&lt;/span&gt;&lt;span class="lnt"&gt;113
&lt;/span&gt;&lt;span class="lnt"&gt;114
&lt;/span&gt;&lt;span class="lnt"&gt;115
&lt;/span&gt;&lt;span class="lnt"&gt;116
&lt;/span&gt;&lt;span class="lnt"&gt;117
&lt;/span&gt;&lt;span class="lnt"&gt;118
&lt;/span&gt;&lt;span class="lnt"&gt;119
&lt;/span&gt;&lt;span class="lnt"&gt;120
&lt;/span&gt;&lt;span class="lnt"&gt;121
&lt;/span&gt;&lt;span class="lnt"&gt;122
&lt;/span&gt;&lt;span class="lnt"&gt;123
&lt;/span&gt;&lt;span class="lnt"&gt;124
&lt;/span&gt;&lt;span class="lnt"&gt;125
&lt;/span&gt;&lt;span class="lnt"&gt;126
&lt;/span&gt;&lt;span class="lnt"&gt;127
&lt;/span&gt;&lt;span class="lnt"&gt;128
&lt;/span&gt;&lt;span class="lnt"&gt;129
&lt;/span&gt;&lt;span class="lnt"&gt;130
&lt;/span&gt;&lt;span class="lnt"&gt;131
&lt;/span&gt;&lt;span class="lnt"&gt;132
&lt;/span&gt;&lt;span class="lnt"&gt;133
&lt;/span&gt;&lt;span class="lnt"&gt;134
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;org\x3f\flamework\base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Database connection above PDO
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @author Donie Leigh &amp;lt;donie.leigh@gmail.com&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @link http://0x3f.org
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @copyright Copyright &amp;amp;copy; 2013-2014 Donie Leigh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @license BSD (3-terms)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DBConnection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var PDO Database connection
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$_c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var array PDO options
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;connection_string&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sqlite::memory:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;pdo_options&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var PDOStatement Last PDO statement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$_lastStmt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Init DB connection
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $dsn DB connection string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $user DB user name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $password DB password
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param array $options PDO options
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_connectDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dsn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;\PDO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dsn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Execute sql statement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param mixed $sql SQL statement or template
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param array $params Parameters for SQL template
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return bool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_connectDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;connection_string&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;driver_options&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sql&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_lastStmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$stmt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$stmt&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Fetch rows
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return array Associative array holding data rows
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getLastStmt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$stmt&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;\PDO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;FETCH_ASSOC&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$rows&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Return the last PDO statement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return PDOStatement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLastStmt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_lastStmt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Begin transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;beginTransaction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;beginTransaction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Commit the current transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Rollback the current transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;rollBack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后实现ActiveRecord类：&lt;/p&gt;</description></item><item><title>PHP框架实战（四）：View的模板与渲染</title><link>http://0x3f.org/posts/flamework-view-rendering/</link><pubDate>Mon, 30 Dec 2013 21:05:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-view-rendering/</guid><description>&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;p&gt;实现MVC模型的&lt;strong&gt;V&lt;/strong&gt;iew层，Controller的Action中应可以将从Model层获取的数据填充到View模板中，并将渲染结果返回给访问者。本文并不志在实现一个完备的模板框架，相应的需求可借助Smarty这样现有的实现。&lt;/p&gt;
&lt;h2 id="获取代码"&gt;获取代码&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout v0.4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="设计与实现"&gt;设计与实现&lt;/h2&gt;
&lt;p&gt;View的模板是最好实现的，因为PHP本身就是一个模板语言，所以这里实现的模板主要是指几条约定：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;模板文件本身是一个普通PHP文件，文件名后缀是“.php”；&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;模板文件应存储在项目指定的模板基础目录中；&lt;/li&gt;
&lt;li&gt;模板名称指模板文件相对于项目的模板基础目录的路径，并且去掉文件后缀；&lt;/li&gt;
&lt;li&gt;模板本身的实际效果等同于在Controller的Action中执行的代码，故可以调用Controller的所有方法以及Flame对象的方法等内容；&lt;/li&gt;
&lt;li&gt;所有要填充到模板中的数据以键值对的形式存储在一个关联数组中，并传递给渲染模板的方法，在模板中使用与键名相同的变量调用数据；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;View的渲染方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;添加Controller::render()方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Render the view template with data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $view View template relative path to base path of the templates
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * For example, &amp;#39;post/list&amp;#39; point to file /srv/http/mysite/protected/view/post/list.php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param array $data Associative array in which data is stored as key-value pairs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EXTR_PREFIX_SAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tpl_&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$viewFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Flame&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getViewPath&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is_readable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$viewFile&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$viewFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FlameException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;View template &lt;/span&gt;&lt;span class="si"&gt;$view&lt;/span&gt;&lt;span class="s2"&gt; does not exist or cannot be readable.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;$view是模板名称，$data是要填充到模板中的数据。&lt;/p&gt;</description></item><item><title>PHP框架实战（三）：实现Controller和Filter</title><link>http://0x3f.org/posts/flamework-controller-and-filter/</link><pubDate>Sun, 29 Dec 2013 20:40:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-controller-and-filter/</guid><description>&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;p&gt;实现Controller和Filter，程序可以从HTTP请求中解析Controller和Action，并在这两个切面级别实现Filter链。此外，在Controller中，可以使用Action的参数直接访问HTTP请求中的同名参数。&lt;/p&gt;
&lt;h2 id="获取代码"&gt;获取代码&lt;/h2&gt;
&lt;p&gt;项目目录结构做了调整，framework目录存放Flamework框架源码，demo目录存放示例项目。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout v0.3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="设计与实现"&gt;设计与实现&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Controller的实现&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;要求请求URL的格式如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://www.mydomain.com/index.php?r=post/save"&gt;http://www.mydomain.com/index.php?r=post/save&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;r&lt;/strong&gt;表示Route，斜杠前面的&lt;strong&gt;post&lt;/strong&gt;表示Controller的名称，后面的&lt;strong&gt;save&lt;/strong&gt;表示Action的名称。对HTTP请求的各种处理逻辑封装在新对象HttpRequest中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt; 10
&lt;/span&gt;&lt;span class="lnt"&gt; 11
&lt;/span&gt;&lt;span class="lnt"&gt; 12
&lt;/span&gt;&lt;span class="lnt"&gt; 13
&lt;/span&gt;&lt;span class="lnt"&gt; 14
&lt;/span&gt;&lt;span class="lnt"&gt; 15
&lt;/span&gt;&lt;span class="lnt"&gt; 16
&lt;/span&gt;&lt;span class="lnt"&gt; 17
&lt;/span&gt;&lt;span class="lnt"&gt; 18
&lt;/span&gt;&lt;span class="lnt"&gt; 19
&lt;/span&gt;&lt;span class="lnt"&gt; 20
&lt;/span&gt;&lt;span class="lnt"&gt; 21
&lt;/span&gt;&lt;span class="lnt"&gt; 22
&lt;/span&gt;&lt;span class="lnt"&gt; 23
&lt;/span&gt;&lt;span class="lnt"&gt; 24
&lt;/span&gt;&lt;span class="lnt"&gt; 25
&lt;/span&gt;&lt;span class="lnt"&gt; 26
&lt;/span&gt;&lt;span class="lnt"&gt; 27
&lt;/span&gt;&lt;span class="lnt"&gt; 28
&lt;/span&gt;&lt;span class="lnt"&gt; 29
&lt;/span&gt;&lt;span class="lnt"&gt; 30
&lt;/span&gt;&lt;span class="lnt"&gt; 31
&lt;/span&gt;&lt;span class="lnt"&gt; 32
&lt;/span&gt;&lt;span class="lnt"&gt; 33
&lt;/span&gt;&lt;span class="lnt"&gt; 34
&lt;/span&gt;&lt;span class="lnt"&gt; 35
&lt;/span&gt;&lt;span class="lnt"&gt; 36
&lt;/span&gt;&lt;span class="lnt"&gt; 37
&lt;/span&gt;&lt;span class="lnt"&gt; 38
&lt;/span&gt;&lt;span class="lnt"&gt; 39
&lt;/span&gt;&lt;span class="lnt"&gt; 40
&lt;/span&gt;&lt;span class="lnt"&gt; 41
&lt;/span&gt;&lt;span class="lnt"&gt; 42
&lt;/span&gt;&lt;span class="lnt"&gt; 43
&lt;/span&gt;&lt;span class="lnt"&gt; 44
&lt;/span&gt;&lt;span class="lnt"&gt; 45
&lt;/span&gt;&lt;span class="lnt"&gt; 46
&lt;/span&gt;&lt;span class="lnt"&gt; 47
&lt;/span&gt;&lt;span class="lnt"&gt; 48
&lt;/span&gt;&lt;span class="lnt"&gt; 49
&lt;/span&gt;&lt;span class="lnt"&gt; 50
&lt;/span&gt;&lt;span class="lnt"&gt; 51
&lt;/span&gt;&lt;span class="lnt"&gt; 52
&lt;/span&gt;&lt;span class="lnt"&gt; 53
&lt;/span&gt;&lt;span class="lnt"&gt; 54
&lt;/span&gt;&lt;span class="lnt"&gt; 55
&lt;/span&gt;&lt;span class="lnt"&gt; 56
&lt;/span&gt;&lt;span class="lnt"&gt; 57
&lt;/span&gt;&lt;span class="lnt"&gt; 58
&lt;/span&gt;&lt;span class="lnt"&gt; 59
&lt;/span&gt;&lt;span class="lnt"&gt; 60
&lt;/span&gt;&lt;span class="lnt"&gt; 61
&lt;/span&gt;&lt;span class="lnt"&gt; 62
&lt;/span&gt;&lt;span class="lnt"&gt; 63
&lt;/span&gt;&lt;span class="lnt"&gt; 64
&lt;/span&gt;&lt;span class="lnt"&gt; 65
&lt;/span&gt;&lt;span class="lnt"&gt; 66
&lt;/span&gt;&lt;span class="lnt"&gt; 67
&lt;/span&gt;&lt;span class="lnt"&gt; 68
&lt;/span&gt;&lt;span class="lnt"&gt; 69
&lt;/span&gt;&lt;span class="lnt"&gt; 70
&lt;/span&gt;&lt;span class="lnt"&gt; 71
&lt;/span&gt;&lt;span class="lnt"&gt; 72
&lt;/span&gt;&lt;span class="lnt"&gt; 73
&lt;/span&gt;&lt;span class="lnt"&gt; 74
&lt;/span&gt;&lt;span class="lnt"&gt; 75
&lt;/span&gt;&lt;span class="lnt"&gt; 76
&lt;/span&gt;&lt;span class="lnt"&gt; 77
&lt;/span&gt;&lt;span class="lnt"&gt; 78
&lt;/span&gt;&lt;span class="lnt"&gt; 79
&lt;/span&gt;&lt;span class="lnt"&gt; 80
&lt;/span&gt;&lt;span class="lnt"&gt; 81
&lt;/span&gt;&lt;span class="lnt"&gt; 82
&lt;/span&gt;&lt;span class="lnt"&gt; 83
&lt;/span&gt;&lt;span class="lnt"&gt; 84
&lt;/span&gt;&lt;span class="lnt"&gt; 85
&lt;/span&gt;&lt;span class="lnt"&gt; 86
&lt;/span&gt;&lt;span class="lnt"&gt; 87
&lt;/span&gt;&lt;span class="lnt"&gt; 88
&lt;/span&gt;&lt;span class="lnt"&gt; 89
&lt;/span&gt;&lt;span class="lnt"&gt; 90
&lt;/span&gt;&lt;span class="lnt"&gt; 91
&lt;/span&gt;&lt;span class="lnt"&gt; 92
&lt;/span&gt;&lt;span class="lnt"&gt; 93
&lt;/span&gt;&lt;span class="lnt"&gt; 94
&lt;/span&gt;&lt;span class="lnt"&gt; 95
&lt;/span&gt;&lt;span class="lnt"&gt; 96
&lt;/span&gt;&lt;span class="lnt"&gt; 97
&lt;/span&gt;&lt;span class="lnt"&gt; 98
&lt;/span&gt;&lt;span class="lnt"&gt; 99
&lt;/span&gt;&lt;span class="lnt"&gt;100
&lt;/span&gt;&lt;span class="lnt"&gt;101
&lt;/span&gt;&lt;span class="lnt"&gt;102
&lt;/span&gt;&lt;span class="lnt"&gt;103
&lt;/span&gt;&lt;span class="lnt"&gt;104
&lt;/span&gt;&lt;span class="lnt"&gt;105
&lt;/span&gt;&lt;span class="lnt"&gt;106
&lt;/span&gt;&lt;span class="lnt"&gt;107
&lt;/span&gt;&lt;span class="lnt"&gt;108
&lt;/span&gt;&lt;span class="lnt"&gt;109
&lt;/span&gt;&lt;span class="lnt"&gt;110
&lt;/span&gt;&lt;span class="lnt"&gt;111
&lt;/span&gt;&lt;span class="lnt"&gt;112
&lt;/span&gt;&lt;span class="lnt"&gt;113
&lt;/span&gt;&lt;span class="lnt"&gt;114
&lt;/span&gt;&lt;span class="lnt"&gt;115
&lt;/span&gt;&lt;span class="lnt"&gt;116
&lt;/span&gt;&lt;span class="lnt"&gt;117
&lt;/span&gt;&lt;span class="lnt"&gt;118
&lt;/span&gt;&lt;span class="lnt"&gt;119
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;org\x3f\flamework\base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;org\x3f\flamework\Flame&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Flame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * HTTP request wrapper
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @author Donie Leigh &amp;lt;donie.leigh@gmail.com&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @link http://0x3f.org
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @copyright Copyright &amp;amp;copy; 2013-2014 Donie Leigh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @license BSD (3-terms)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var HttpRequest Singleton instance
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nv"&gt;$_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var string Controller name, null if no one is given
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$_controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var string Action name, null if no one is given
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$_action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Singleton constructor
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;parseRoute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Disable the cloning
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;trigger_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Clone is not allow!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;E_USER_ERROR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Get the singleton instance
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return HttpRequest
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$_instance&lt;/span&gt; &lt;span class="nx"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Parse request route, set controller and action names
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseRoute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Flame&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getDefaultController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Get controller name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return string null if no controller is present
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Get action name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return string null if no action is found
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Get parameter value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $param Parameter name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return mixed Parameter value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_REQUEST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$_REQUEST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;考虑到HttpRequest可能在多个地方被调用，所以用单例模式实现。&lt;/p&gt;</description></item><item><title>PHP框架实战（二）：错误和异常的自动处理</title><link>http://0x3f.org/posts/flamework-error-auto-handling/</link><pubDate>Sat, 28 Dec 2013 13:40:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-error-auto-handling/</guid><description>&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;p&gt;实现错误和异常的自动捕获和处理。&lt;/p&gt;
&lt;h2 id="获取代码"&gt;获取代码&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout v0.2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="设计与实现"&gt;设计与实现&lt;/h2&gt;
&lt;p&gt;使用set_error_handler()和set_exception_handler()两个函数注册错误和异常的处理方法，并在两个处理方法中先调用用户自定义的错误和异常处理逻辑，如果自定义逻辑不存在或者返回false，继续调用框架缺省的处理逻辑，输出错误信息到页面。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt; 10
&lt;/span&gt;&lt;span class="lnt"&gt; 11
&lt;/span&gt;&lt;span class="lnt"&gt; 12
&lt;/span&gt;&lt;span class="lnt"&gt; 13
&lt;/span&gt;&lt;span class="lnt"&gt; 14
&lt;/span&gt;&lt;span class="lnt"&gt; 15
&lt;/span&gt;&lt;span class="lnt"&gt; 16
&lt;/span&gt;&lt;span class="lnt"&gt; 17
&lt;/span&gt;&lt;span class="lnt"&gt; 18
&lt;/span&gt;&lt;span class="lnt"&gt; 19
&lt;/span&gt;&lt;span class="lnt"&gt; 20
&lt;/span&gt;&lt;span class="lnt"&gt; 21
&lt;/span&gt;&lt;span class="lnt"&gt; 22
&lt;/span&gt;&lt;span class="lnt"&gt; 23
&lt;/span&gt;&lt;span class="lnt"&gt; 24
&lt;/span&gt;&lt;span class="lnt"&gt; 25
&lt;/span&gt;&lt;span class="lnt"&gt; 26
&lt;/span&gt;&lt;span class="lnt"&gt; 27
&lt;/span&gt;&lt;span class="lnt"&gt; 28
&lt;/span&gt;&lt;span class="lnt"&gt; 29
&lt;/span&gt;&lt;span class="lnt"&gt; 30
&lt;/span&gt;&lt;span class="lnt"&gt; 31
&lt;/span&gt;&lt;span class="lnt"&gt; 32
&lt;/span&gt;&lt;span class="lnt"&gt; 33
&lt;/span&gt;&lt;span class="lnt"&gt; 34
&lt;/span&gt;&lt;span class="lnt"&gt; 35
&lt;/span&gt;&lt;span class="lnt"&gt; 36
&lt;/span&gt;&lt;span class="lnt"&gt; 37
&lt;/span&gt;&lt;span class="lnt"&gt; 38
&lt;/span&gt;&lt;span class="lnt"&gt; 39
&lt;/span&gt;&lt;span class="lnt"&gt; 40
&lt;/span&gt;&lt;span class="lnt"&gt; 41
&lt;/span&gt;&lt;span class="lnt"&gt; 42
&lt;/span&gt;&lt;span class="lnt"&gt; 43
&lt;/span&gt;&lt;span class="lnt"&gt; 44
&lt;/span&gt;&lt;span class="lnt"&gt; 45
&lt;/span&gt;&lt;span class="lnt"&gt; 46
&lt;/span&gt;&lt;span class="lnt"&gt; 47
&lt;/span&gt;&lt;span class="lnt"&gt; 48
&lt;/span&gt;&lt;span class="lnt"&gt; 49
&lt;/span&gt;&lt;span class="lnt"&gt; 50
&lt;/span&gt;&lt;span class="lnt"&gt; 51
&lt;/span&gt;&lt;span class="lnt"&gt; 52
&lt;/span&gt;&lt;span class="lnt"&gt; 53
&lt;/span&gt;&lt;span class="lnt"&gt; 54
&lt;/span&gt;&lt;span class="lnt"&gt; 55
&lt;/span&gt;&lt;span class="lnt"&gt; 56
&lt;/span&gt;&lt;span class="lnt"&gt; 57
&lt;/span&gt;&lt;span class="lnt"&gt; 58
&lt;/span&gt;&lt;span class="lnt"&gt; 59
&lt;/span&gt;&lt;span class="lnt"&gt; 60
&lt;/span&gt;&lt;span class="lnt"&gt; 61
&lt;/span&gt;&lt;span class="lnt"&gt; 62
&lt;/span&gt;&lt;span class="lnt"&gt; 63
&lt;/span&gt;&lt;span class="lnt"&gt; 64
&lt;/span&gt;&lt;span class="lnt"&gt; 65
&lt;/span&gt;&lt;span class="lnt"&gt; 66
&lt;/span&gt;&lt;span class="lnt"&gt; 67
&lt;/span&gt;&lt;span class="lnt"&gt; 68
&lt;/span&gt;&lt;span class="lnt"&gt; 69
&lt;/span&gt;&lt;span class="lnt"&gt; 70
&lt;/span&gt;&lt;span class="lnt"&gt; 71
&lt;/span&gt;&lt;span class="lnt"&gt; 72
&lt;/span&gt;&lt;span class="lnt"&gt; 73
&lt;/span&gt;&lt;span class="lnt"&gt; 74
&lt;/span&gt;&lt;span class="lnt"&gt; 75
&lt;/span&gt;&lt;span class="lnt"&gt; 76
&lt;/span&gt;&lt;span class="lnt"&gt; 77
&lt;/span&gt;&lt;span class="lnt"&gt; 78
&lt;/span&gt;&lt;span class="lnt"&gt; 79
&lt;/span&gt;&lt;span class="lnt"&gt; 80
&lt;/span&gt;&lt;span class="lnt"&gt; 81
&lt;/span&gt;&lt;span class="lnt"&gt; 82
&lt;/span&gt;&lt;span class="lnt"&gt; 83
&lt;/span&gt;&lt;span class="lnt"&gt; 84
&lt;/span&gt;&lt;span class="lnt"&gt; 85
&lt;/span&gt;&lt;span class="lnt"&gt; 86
&lt;/span&gt;&lt;span class="lnt"&gt; 87
&lt;/span&gt;&lt;span class="lnt"&gt; 88
&lt;/span&gt;&lt;span class="lnt"&gt; 89
&lt;/span&gt;&lt;span class="lnt"&gt; 90
&lt;/span&gt;&lt;span class="lnt"&gt; 91
&lt;/span&gt;&lt;span class="lnt"&gt; 92
&lt;/span&gt;&lt;span class="lnt"&gt; 93
&lt;/span&gt;&lt;span class="lnt"&gt; 94
&lt;/span&gt;&lt;span class="lnt"&gt; 95
&lt;/span&gt;&lt;span class="lnt"&gt; 96
&lt;/span&gt;&lt;span class="lnt"&gt; 97
&lt;/span&gt;&lt;span class="lnt"&gt; 98
&lt;/span&gt;&lt;span class="lnt"&gt; 99
&lt;/span&gt;&lt;span class="lnt"&gt;100
&lt;/span&gt;&lt;span class="lnt"&gt;101
&lt;/span&gt;&lt;span class="lnt"&gt;102
&lt;/span&gt;&lt;span class="lnt"&gt;103
&lt;/span&gt;&lt;span class="lnt"&gt;104
&lt;/span&gt;&lt;span class="lnt"&gt;105
&lt;/span&gt;&lt;span class="lnt"&gt;106
&lt;/span&gt;&lt;span class="lnt"&gt;107
&lt;/span&gt;&lt;span class="lnt"&gt;108
&lt;/span&gt;&lt;span class="lnt"&gt;109
&lt;/span&gt;&lt;span class="lnt"&gt;110
&lt;/span&gt;&lt;span class="lnt"&gt;111
&lt;/span&gt;&lt;span class="lnt"&gt;112
&lt;/span&gt;&lt;span class="lnt"&gt;113
&lt;/span&gt;&lt;span class="lnt"&gt;114
&lt;/span&gt;&lt;span class="lnt"&gt;115
&lt;/span&gt;&lt;span class="lnt"&gt;116
&lt;/span&gt;&lt;span class="lnt"&gt;117
&lt;/span&gt;&lt;span class="lnt"&gt;118
&lt;/span&gt;&lt;span class="lnt"&gt;119
&lt;/span&gt;&lt;span class="lnt"&gt;120
&lt;/span&gt;&lt;span class="lnt"&gt;121
&lt;/span&gt;&lt;span class="lnt"&gt;122
&lt;/span&gt;&lt;span class="lnt"&gt;123
&lt;/span&gt;&lt;span class="lnt"&gt;124
&lt;/span&gt;&lt;span class="lnt"&gt;125
&lt;/span&gt;&lt;span class="lnt"&gt;126
&lt;/span&gt;&lt;span class="lnt"&gt;127
&lt;/span&gt;&lt;span class="lnt"&gt;128
&lt;/span&gt;&lt;span class="lnt"&gt;129
&lt;/span&gt;&lt;span class="lnt"&gt;130
&lt;/span&gt;&lt;span class="lnt"&gt;131
&lt;/span&gt;&lt;span class="lnt"&gt;132
&lt;/span&gt;&lt;span class="lnt"&gt;133
&lt;/span&gt;&lt;span class="lnt"&gt;134
&lt;/span&gt;&lt;span class="lnt"&gt;135
&lt;/span&gt;&lt;span class="lnt"&gt;136
&lt;/span&gt;&lt;span class="lnt"&gt;137
&lt;/span&gt;&lt;span class="lnt"&gt;138
&lt;/span&gt;&lt;span class="lnt"&gt;139
&lt;/span&gt;&lt;span class="lnt"&gt;140
&lt;/span&gt;&lt;span class="lnt"&gt;141
&lt;/span&gt;&lt;span class="lnt"&gt;142
&lt;/span&gt;&lt;span class="lnt"&gt;143
&lt;/span&gt;&lt;span class="lnt"&gt;144
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebApplication&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var boolean Whether to enable error auto-handling, default to true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$enableErrorHandling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var boolean Whether to enable exception auto-handling, default to true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$enableExceptionHandling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var callable Error handler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$errorHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var callable Exception handler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$exceptionHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @var boolean Whether to enable debug mode, default to false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$debug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $config
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;initErrorHandlers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Initialize auto-handling for errors and exceptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;initErrorHandlers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;enableErrorHandling&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;set_error_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;handleError&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;error_reporting&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;enableExceptionHandling&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;set_exception_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;handleException&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Handle errors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param int $code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $message
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param int $line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// prevent recursive errors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;restore_error_handler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;restore_exception_handler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Error &lt;/span&gt;&lt;span class="si"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;$message&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;)&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Flame&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// let errorHandler() return true to prevent displayError()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is_callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;call_user_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Handle exceptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param Exception $exception
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// prevent recursive errors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;restore_error_handler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;restore_exception_handler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getTraceAsString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Flame&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// let exceptionHandler() return true to prevent displayException()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is_callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;exceptionHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;call_user_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;exceptionHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;displayException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Display error information
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param int $code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $message
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param string $file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param int $line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;h1&amp;gt;Error &lt;/span&gt;&lt;span class="si"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;$message&lt;/span&gt;&lt;span class="s2"&gt; in (&lt;/span&gt;&lt;span class="si"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;)&amp;lt;/p&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;pre&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;debug_print_backtrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;/pre&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;h1&amp;gt;Error &lt;/span&gt;&lt;span class="si"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;$message&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sd"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * Display exception information
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @param Exception $exception
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @return void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; * @since 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;displayException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;/h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;p&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)&amp;lt;/p&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;pre&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getTraceAsString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;/pre&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;/h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;p&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;/p&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;“handleError()”和“handleException()”中先调用了“restore_error_handler()”和“restore_exception_handler()”，用于防止递归处理。&lt;/p&gt;</description></item><item><title>PHP框架实战（一）：框架入口与类的自动加载</title><link>http://0x3f.org/posts/flamework-entry/</link><pubDate>Sat, 28 Dec 2013 01:56:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-entry/</guid><description>&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;p&gt;实现框架入口和类的自动加载。&lt;/p&gt;
&lt;h2 id="获取代码"&gt;获取代码&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout v0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="设计与实现"&gt;设计与实现&lt;/h2&gt;
&lt;p&gt;通过两个类实现本次目标。&lt;/p&gt;
&lt;p&gt;静态类Flame作为整个框架的入口，实现一系列框架级公用静态方法（&lt;em&gt;例如创建应用实例和自动加载类&lt;/em&gt;）。&lt;/p&gt;
&lt;p&gt;WebApplication是应用的抽象层，实现应用的入口和其它应用级（&lt;strong&gt;即运行时&lt;/strong&gt;）公用方法（&lt;em&gt;例如读取配置文件&lt;/em&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;程序入口&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Flame&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;createApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;此处传入的$config是应用配置文件的路径，该配置文件内容格式如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;opt1&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;val1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在文件中直接return一个关联数组的好处是，加载该文件时，include()函数的返回值就是该数组，代码更简洁，效率比解析其它格式配置文件高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;类的自动加载&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Flame&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;autoload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$className&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$_namespaces&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;__NAMESPACE__&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$_namespaces&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;__NAMESPACE__&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$_namespaces&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$ns&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strpos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$ns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$classFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;str_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\\&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ns&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$classFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;class_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$className&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;spl_autoload_register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;__NAMESPACE__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\\Flame::autoload&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;通过函数spl_autoload_register()注册Flame::autoload()方法。当用到一个类时，PHP会先检查该类是否已加载，如果没有，就把包括命名空间在内的完整的类名传递给autoload()，最终完成类的加载。&lt;/p&gt;</description></item><item><title>PHP框架实战（零）：代码规范</title><link>http://0x3f.org/posts/flamework-code-spec/</link><pubDate>Thu, 26 Dec 2013 22:07:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework-code-spec/</guid><description>&lt;p&gt;类C语言语法风格最大的问题就是用花括号区分代码块，这导致源码排版容易混乱，对于我这种有代码洁癖的人来说非常痛苦，所以我最喜欢的语法风格是Python的，用缩进区分代码块，排版不规范直接判处语法错误。&lt;/p&gt;
&lt;h2 id="命名规范"&gt;命名规范&lt;/h2&gt;
&lt;p&gt;所有命名使用驼峰风格。&lt;/p&gt;
&lt;p&gt;源码开头定义命名空间，Flamework框架入口类的命名空间为“&lt;strong&gt;org\x3f\flamework&lt;/strong&gt;”，其余类的命名空间应在此基础上追加与所在目录路径匹配的内容。例如，框架源码目录下一级子目录“base”中的类文件的命名空间均为“org\x3f\flamework\base”。&lt;/p&gt;
&lt;p&gt;类名必须是名词，不允许添加任何无意义的前缀或后缀，只允许使用大小写英文字母且首字母大写。&lt;/p&gt;
&lt;p&gt;方法名必须是“动词+名词”的形式（&lt;em&gt;如果动词意义明确且不需要宾语，可省略后者&lt;/em&gt;），只允许使用大小写英文字母及阿拉伯数字和下划线，首字母小写。&lt;/p&gt;
&lt;p&gt;属性名分两种情况，对于存储普通数据的属性，名称必须是名词；对于布尔型属性，名称必须是“动词+名词”的形式。只允许使用大小写英文字母及阿拉伯数字和下划线，首字母小写。&lt;/p&gt;
&lt;p&gt;源码文件名必须与类名相同，后缀统一使用“.php”。&lt;/p&gt;
&lt;h2 id="注释规范"&gt;注释规范&lt;/h2&gt;
&lt;p&gt;统一使用&lt;a href="http://www.phpdoc.org/"&gt;phpDocumenter&lt;/a&gt;的注释规范。&lt;/p&gt;
&lt;p&gt;类注释必须注明@author、@since。&lt;/p&gt;
&lt;p&gt;属性和方法的作者如果和类的创建者不同，必须注明@author，此外必须注明@since。&lt;/p&gt;
&lt;h2 id="文件格式"&gt;文件格式&lt;/h2&gt;
&lt;p&gt;所有文本文件统一使用UNIX格式和UTF-8编码。&lt;/p&gt;
&lt;p&gt;严禁使用制表符缩进代码，必须使用4个空格替代制表符。&lt;/p&gt;
&lt;p&gt;类、属性、方法、方法内部代码块都必须严格按照层级缩进。&lt;/p&gt;</description></item><item><title>PHP框架实战：Flamework</title><link>http://0x3f.org/posts/flamework/</link><pubDate>Thu, 26 Dec 2013 20:24:00 +0000</pubDate><guid>http://0x3f.org/posts/flamework/</guid><description>&lt;p&gt;从今天开始，逐步实现一个PHP的MVC框架，以践行平时对这方面的一些想法。&lt;/p&gt;
&lt;h2 id="项目信息"&gt;项目信息&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;名称：Flamework (&lt;em&gt;Flame Framework&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;源码：https://github.com/xbot/flamework&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="框架特性"&gt;框架特性&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;激进&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用PHP高版本引入的新特性，不考虑向前兼容问题，没有历史包袱。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;命名空间&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PHP 5.3引入的命名空间可以有效避免类命名冲突，这样可以使类名看起来更自然，不用再在类名前面加难看的前缀了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;类的自动加载&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;手动include会增加维护的难度，因为经常会出现一个类被从源码中移除而它的include行还在的问题，这会拖慢程序执行速度、增加内存占用。&lt;/p&gt;
&lt;p&gt;实现类的自动加载可以在类被引用时自动include相应的源码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;异常的自动处理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在设计程序时，一般应该把用户级的错误返回给页面显示，或者对一些HTTP错误显示个性化的页面（&lt;em&gt;例如人民群众喜闻乐见的404页面&lt;/em&gt;），所以在业务逻辑、数据操作这些层一般应该逐级向上抛异常，然后在Controller里捕获并加工成页面可识别的格式（&lt;em&gt;例如JSON&lt;/em&gt;）。这样做的缺点是Controller里每个Action都包含重复的try&amp;hellip;catch块。&lt;/p&gt;
&lt;p&gt;异常的自动处理允许开发者指定自定义的异常处理逻辑，将异常处理与普通逻辑解耦，这样每个Action只需实现它所关注的功能即可。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;过滤器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;过滤器允许面向切面编程，是将横向逻辑与纵向逻辑解耦的重要工具。Flamework要实现针对Controller和Action两个级别的过滤器链，过滤器可在该级别逻辑前后执行，并能停止该级别逻辑及后续过滤器的执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;懒加载&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对尽可能多的资源实现懒加载，例如数据库连接、类、组件等，目的是提高效率、节约资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数绑定&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;自动将请求中的参数与Action方法的参数绑定，从而避免在Action里出现通过$_POST、$_GET这些数组取参数的脏代码，也可以自动实现参数的校验和错误处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ActiveRecord&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ORM是对关系模型和对象模型的阻抗不匹配问题的解决方案，ActiveRecord是目前最流行的一种ORM的实现方式。通过AR，可以以更对象化的方式操作关系数据库的数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;依赖注入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;依赖注入是个很好的解耦方法，也可以很优雅地实现懒加载。&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-code-spec"&gt;零：代码规范&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-entry"&gt;一：框架入口与类的自动加载&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-error-auto-handling"&gt;二：错误和异常的自动处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-controller-and-filter"&gt;三：实现Controller和Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-view-rendering"&gt;四：视图的模板与渲染&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-active-record"&gt;五：ORM与ActiveRecord&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-dependency-injection"&gt;六：依赖注入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/flamework-summary"&gt;∝：烈焰之终章&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>这半年读过的几本书</title><link>http://0x3f.org/posts/books-read-in-the-second-half-of-2013/</link><pubDate>Wed, 25 Dec 2013 23:10:00 +0000</pubDate><guid>http://0x3f.org/posts/books-read-in-the-second-half-of-2013/</guid><description>&lt;p&gt;微博一度使我更新博客的频率一降再降，现在我决定回归。已经写了七年，依然乐此不疲。&lt;/p&gt;
&lt;p&gt;这半年去过一些地方，读过一些书，顿悟了一些东西，我是个有一身毛病的动物，但我享受debug的过程。&lt;/p&gt;
&lt;p&gt;现在读书的动力很大程度上来自于使用PaperWhite的愉悦感，虽然最初买电子书阅读器的目的是读盗版，不过现在宁愿为了更好的排版而买正版，而且觉得更过瘾。现在我在买一本书前都要先看有没有电子版，没有的话就去找盗版，连盗版都没有才去买印刷版。&lt;/p&gt;
&lt;h2 id="小通鉴"&gt;小通鉴&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpCW6kFR/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;虽然《通鉴》读了三年还没有读完，这本小书却很快就过了一遍。它从通鉴里抽出了几个故事，展开评论了一下。读了原史再看别人的解读，经常会会心一笑，或心有戚戚，或醍醐灌顶。读史最大的好处有两个，一是学做事，一是学做人，我注六经，六经注我。&lt;/p&gt;
&lt;h2 id="诛仙"&gt;诛仙&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpD1kbUK/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;纯粹是为了了结旧账，这书在我还在学校的时候还没写完，隔了多年，画一个圈圈，终结它。书本身的故事不错，本来可以再深挖一些，可惜被文笔糟蹋了，整本书缩写为原来的一百分之一波形不会有失真。&lt;/p&gt;
&lt;h2 id="我所认识的蒋介石"&gt;我所认识的蒋介石&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpD2nJlC/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;这本书只读了开头就读不下去了，对于历史和历史人物，全面肯定和全面否定都是不可信的。&lt;/p&gt;
&lt;h2 id="大漠苍狼绝密飞行"&gt;大漠苍狼：绝密飞行&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpD5NoG1/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;悬疑设定得不错。不过现在越来越不喜欢有恐怖色彩的东西，所以这可能是我最后看的一本这种题材的书。&lt;/p&gt;
&lt;h2 id="javascript权威指南"&gt;Javascript权威指南&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpD6JS7c/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;传说中的犀牛书，Javascript最权威的资料之一。第一部分“语言核心”是要细读的，第二部分“客户端的JS”对有几年经验的人，从13到18章浏览一遍，之后的用康圣人读书法。读完这本书就知道什么叫生命不息挖坑不止。&lt;/p&gt;
&lt;h2 id="精通css"&gt;精通CSS&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpD860nd/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;本想查漏补缺，所以没选《CSS禅意花园》，结果这书还是偏设计。难道这个星球上就没有一本给非前端开发看的CSS书么？&lt;/p&gt;
&lt;h2 id="spring-in-action"&gt;Spring in Action&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpD9xCFY/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;重新寻找丢掉的青春，撂下五年再拾起来容易么。这书是本不错的Spring初级教材。&lt;/p&gt;
&lt;h2 id="板桥杂记"&gt;板桥杂记&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpDblJwq/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;明末清初大才子余怀的招嫖回忆录，从对江南名妓的记述中映射物是人非之慨，文笔绝佳。秋风团扇，一觉扬州，于字字雕琢中见山河离碎、愁绪盈怀。每个危楼听雨的暮年都有著软红十丈的青春。&lt;/p&gt;
&lt;h2 id="nosql精粹"&gt;NoSQL精粹&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/DpDdM5l4/medish.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;NoSQL绝佳的一本入门教材，对NoSQL的概念、应用场景、各类实现的优缺点等等都有适度的介绍。对于一直使用传统技术的人而言，这本书有醍醐灌顶使人捶胸顿足怒相见恨晚叹青春易逝之副作用。&lt;/p&gt;</description></item><item><title>用 Dojo 实现拖放操作的最佳实践</title><link>http://0x3f.org/posts/practical-drag-and-drop-implementation-with-dojo/</link><pubDate>Tue, 05 Nov 2013 16:58:00 +0000</pubDate><guid>http://0x3f.org/posts/practical-drag-and-drop-implementation-with-dojo/</guid><description>&lt;p&gt;在研究 Dojo 实现拖放操作时，我花了很多时间处理一些细节问题，比如创建自定义样式的拖拽物件以及将光标放置在拖拽开始位置等。这些细节在实现个性化的拖放操作时非常重要，但是我几乎没有找到直接相关的资料可供参考。&lt;/p&gt;
&lt;h2 id="创建自定义样式的拖拽物件"&gt;创建自定义样式的拖拽物件&lt;/h2&gt;
&lt;p&gt;Dojo 缺省的拖拽物件样式很丑，通过覆盖官方文档里列出的几个 CSS 的 class 可以有限地调整部分样式，如果需要更多个性化，就需要使用自定义的物件模板。&lt;/p&gt;
&lt;p&gt;通过重载 Source 对象的 creator 方法可以实现这一点。这个方法会在创建拖拽物件的时候被调用，如果 hint 参数的值为“avatar”就表示将被创建的是被拖拽物件，此时可以使用预先定义好的模板 avatarTmpl 创建物件的 node 。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dndSrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;copyOnly&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;selfAccept&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;creator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hint&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;avatar&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;domConstruct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;avatarTmpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="置光标位置于拖拽起始处"&gt;置光标位置于拖拽起始处&lt;/h2&gt;
&lt;p&gt;在拖拽开始后，Dojo 默认将光标置于被拖拽物件的左上角，而一般把光标置于拖拽开始时相对于物件的位置处显得比较自然。&lt;/p&gt;
&lt;p&gt;实现方式是先记录拖拽开始时光标的位置，然后设置 dojo.dnd.Manager 的两个位移属性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;mousedown&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_setDndOffset&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;_setDndOffset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// summary: 鼠标按下时将光标相对于组件的位移设置为dojo.dnd.Manager的位移
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 即使光标在拖动开始后位于拖动开始时的位置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCursorPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;nPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;domGeometry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;OFFSET_X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nPos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cPos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;OFFSET_Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nPos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cPos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="使鼠标事件穿透被拖拽物件"&gt;使鼠标事件穿透被拖拽物件&lt;/h2&gt;
&lt;p&gt;将光标置于物件开始被拖拽时的位置后，物件本身会挡住 mouseover 事件，导致 Target 不能获知物件被拖拽到自己上方，以致能拖不能放。&lt;/p&gt;</description></item><item><title>IE中使用IFrame上传文件报错——TypeError:拒绝访问</title><link>http://0x3f.org/posts/typeerror-access-denied/</link><pubDate>Sat, 03 Aug 2013 01:03:00 +0000</pubDate><guid>http://0x3f.org/posts/typeerror-access-denied/</guid><description>&lt;p&gt;场景为：&lt;/p&gt;
&lt;p&gt;点击一个图标，打开文件选择对话框，选择好文件后即时上传。&lt;/p&gt;
&lt;p&gt;之前的实现方式是在一个隐藏表单中放一个file类型的input元素，通过调用input.click()打开对话框，同时监听input.onchange，最后通过dojo/request/iframe上传文件。&lt;/p&gt;
&lt;p&gt;这个实现方式在Chrome和Firefox里都没问题，但是在IE里报错：“&lt;strong&gt;TypeError:拒绝访问&lt;/strong&gt;”。原因是IE要求必须通过点击file类型的input的按钮打开选择对话框，否则就报这个错误。&lt;/p&gt;
&lt;p&gt;解决办法是修改input元素的样式，或者直接用dojox.form.Uploader替代。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;因为这个破问题又血战到半夜，只支持IE9+的世界你们好吗，还支持IE7+的屌丝伤不起……不起……起……啊。&lt;strong&gt;IE不死，吾难未已！！！&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Dojo DnD: Cannot read property 'type' of undefined</title><link>http://0x3f.org/posts/dojo-dnd-cannot-read-property-type-of-undefined/</link><pubDate>Thu, 11 Jul 2013 22:44:00 +0000</pubDate><guid>http://0x3f.org/posts/dojo-dnd-cannot-read-property-type-of-undefined/</guid><description>&lt;p&gt;场景如下：&lt;/p&gt;
&lt;p&gt;假设有两个Widget：ItemListWidget和ItemWidget，后者要被创建多份并追加到前者内部，同时ItemListWidget要作为dojo/dnd/Source，每个ItemWidget作为一个单元可被拖拽到另外一个dojo/dnd/Target容器中。&lt;/p&gt;
&lt;p&gt;问题是，当Source被创建后，再添加到ItemListWidget的ItemWidget实例在被拖拽时会报如下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Uncaught TypeError: Cannot read property &amp;rsquo;type&amp;rsquo; of undefined&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在Chrome开发工具中点开这个错误，显示以下内容：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/D0dD4euT/cULuA.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;从方法的注释或API中可以看到，checkAcceptance()是用来判断当前拖拽对象是否在这个target接受的范围之内，接受规则用Source和Target的构造参数中的“accept”定义。在这个方法里通过Source.getItem()方法拿到的对象是null，上述错误就是从这儿报出来的。&lt;/p&gt;
&lt;p&gt;接合API和Reference Guide发现，每个Source中的可拖拽项目在Source中都要有一个对应的对象，这个对象至少包括两个属性：“data”和“type”。在&lt;a href="http://dojotoolkit.org/reference-guide/1.9/dojo/dnd.html"&gt;Reference Guide&lt;/a&gt;中，对这两个属性有详细说明，简言之，data是向Target传递的数据，type是被Target用来判断拖拽个体是否属于接受范围的依据。&lt;/p&gt;
&lt;p&gt;当Source实例被创建时，已经存在于ItemListWidget中的ItemWidget实例会被自动创建对应的上述对象，但之后加入的不会。解决的办法是调用Source.setItem()方法为每一个新加入的ItemWidget关联相应的对象，或在ItemWidget中添加一个构造参数，用于指定Source，并在postCreate()方法中为当前ItemWidget实例关联相应的对象:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dojo/_base/declare&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dijit/_WidgetBase&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_WidgetBase&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ItemWidget&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_WidgetBase&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 本Widget实例所属的Source实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;dndSrc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;postCreate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inherited&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 不需要传递数据时，可忽略data参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dndSrc&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dndSrc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Take Sakura as My Primary Terminal</title><link>http://0x3f.org/posts/take-sakura-as-my-primary-terminal/</link><pubDate>Sun, 07 Jul 2013 12:07:00 +0000</pubDate><guid>http://0x3f.org/posts/take-sakura-as-my-primary-terminal/</guid><description>&lt;p&gt;It&amp;rsquo;s a long time since I came across rxvt-unicode.&lt;/p&gt;
&lt;p&gt;About seven years ago, when I switched from Windows XP to Ubuntu mainly for performance issues, I never be bored with searching for everything with a higher speed. To me, gnome-terminal is too much slow as a terminal being frequently opened and closed. Then, rxvt-unicode came through.&lt;/p&gt;
&lt;p&gt;At first glance, rxvt-unicode was so ugly that I put it behind without the slightest bit of hesitation. Not until I once saw a screenshot did I realize this ugly thing can actually be pretty like that. So I started to take it as my primary terminal since then, for it was the fastest terminal I can find at that time.&lt;/p&gt;</description></item><item><title>读完《悟空传》</title><link>http://0x3f.org/posts/after-reading-wukongs-biography/</link><pubDate>Fri, 05 Jul 2013 23:12:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-wukongs-biography/</guid><description>&lt;p&gt;&lt;strong&gt;我要这天，再遮不住我眼；要这地，再埋不了我心；要这众生，都明白我意；要那诸佛，都烟消云散！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是本适合少年读、青年悟、中年回味的书，很遗憾没有在我最好的几年里读过它。到了没有激情和理想的年龄，已经不能耐著性子读这种需要花时间和动脑子的书，这次在Kindle PaperWhite上匆匆翻完，我知道可能需要很多年去慢慢的品。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CZj8ATdH/medish.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>PySide: How to Get the Position of a Widget-Value-Changed Cell in QTableWidget</title><link>http://0x3f.org/posts/get-position-in-qtablewidget-for-changed-cellwidgets/</link><pubDate>Mon, 01 Jul 2013 00:57:00 +0000</pubDate><guid>http://0x3f.org/posts/get-position-in-qtablewidget-for-changed-cellwidgets/</guid><description>&lt;p&gt;Assume we have created an instance of QTableWidget, in which cells are filled with widgets like QComboBox, QCheckBox, etc. When values are changed, we need to get the row and column indexes of the cells. But the QTableWidget.cellChanged() and QTableWidget.itemChanged() signals are only effective for cells containing QTableWidgetItem instances, for those in which widgets are filled in with QTableWidget.setCellWidget(), this doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;This problem nearly made me crazy last weekend. So how can I make it ?&lt;/p&gt;</description></item><item><title>那些年我用过的鼠标</title><link>http://0x3f.org/posts/my-mouses-of-all-those-years/</link><pubDate>Sat, 29 Jun 2013 19:53:00 +0000</pubDate><guid>http://0x3f.org/posts/my-mouses-of-all-those-years/</guid><description>&lt;p&gt;第四款，罗技M185，卖相不错，无光，一节五号电池驱动，据说很省电，握感不错，正在用。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CYn6F5gI/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;第三款，惠普百灵，卖相不错，大小适中，左侧两个快捷按键在浏览网页时前进后退很方便。两节七号电池驱动，不太省电。先后买过两个，都是滚轮失灵，似乎这款的滚轮有问题，伤心了。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CYn6Fr6q/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;第二款，雷柏7100，形状较大，握感还可以，用一节五号电池，省电。最后按键失灵，壮烈牺牲。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CYn6G96i/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;第一款，Thinkpad 31P7410，先后买过两三个，比较小巧，按键易坏，不推荐。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CYn6Fkha/medium.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>读完《背包十年》</title><link>http://0x3f.org/posts/after-reading-ten-years-of-traveling/</link><pubDate>Thu, 06 Jun 2013 22:12:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-ten-years-of-traveling/</guid><description>&lt;p&gt;年龄越大，越有种对失去自由的恐惧。“老牛自知夕阳晚，不用扬鞭自奋蹄”，于是越来越想走得远点儿，然后就看到了这本书。这是我第一次正经买电子书，花了3￥，用了五天的时间。&lt;/p&gt;
&lt;p&gt;这是本游记，主要讲的是作者十年旅行的见闻和心路历程，从自然平实的词句中可以看出作者心态很平和，能体会这种心态，已经很好。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CUTfChw6/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PS: 有点淡淡的忧桑，今天，我高考十年……&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>How to Make YouCompleteMe Compatible with UltiSnips</title><link>http://0x3f.org/posts/make-youcompleteme-ultisnips-compatible/</link><pubDate>Thu, 23 May 2013 11:26:00 +0000</pubDate><guid>http://0x3f.org/posts/make-youcompleteme-ultisnips-compatible/</guid><description>&lt;p&gt;I replaced &lt;a href="https://github.com/Shougo/neocomplcache"&gt;NeoComplCache&lt;/a&gt; with &lt;a href="https://github.com/Valloric/YouCompleteMe"&gt;YouCompleteMe&lt;/a&gt; today. The main reason is for the auto-complete feature and the fast speed. Besides, it seems that YCM provides more features than NCC.&lt;/p&gt;
&lt;p&gt;Although NCC can also do auto-completions, it was so slow that I had to turn it off. For a long time, I have been doing completions by triggering the TAB key manually. YCM is much faster in most conditions, but I found it is also slow for C source files. Moreover, with the power of &lt;a href="https://github.com/davidhalter/jedi"&gt;jedi&lt;/a&gt;, YCM makes completions of python sources much wiser, which is very convenient.&lt;/p&gt;</description></item><item><title>Vundle vs Pathogen</title><link>http://0x3f.org/posts/vundle-vs-pathogen/</link><pubDate>Wed, 22 May 2013 21:33:00 +0000</pubDate><guid>http://0x3f.org/posts/vundle-vs-pathogen/</guid><description>&lt;p&gt;I have been using Pathogen for a long time and I am happy with it. But it seems that more and more Vim scripts are recommending to use Vundle in their install references. So I made a study today, the conclusion is, although almost all the articles I found from Google have a positive attitude on Vundle, I still prefer Pathogen.&lt;/p&gt;
&lt;p&gt;Most supporters of Vundle praise it for one reason, that is, it can install and update scripts automatically, which is lacked by Pathogen. Yes, since Vundle leverages the vim-scripts repository on GitHub, it is really easier to do so than Pathogen. But the disadvantage is as good as the advantage. I found that the vim-scripts repo is not updated in time, the latest activity was carried out a month ago ! As an OCD patient of updating, I cannot tolerate old versions of vim scripts. Although that Vundle supports using scripts&amp;rsquo; git repos of their own (either on GitHub or other places), there is still a problem, what if authors commit broken code to the master brunch ?&lt;/p&gt;</description></item><item><title>骑行京西古道</title><link>http://0x3f.org/posts/riding-to-ancient-west-peking-path/</link><pubDate>Sat, 18 May 2013 22:09:00 +0000</pubDate><guid>http://0x3f.org/posts/riding-to-ancient-west-peking-path/</guid><description>&lt;p&gt;13年5月，骑行京西古道。&lt;/p&gt;
&lt;p&gt;从水峪嘴下去，进京西古道风景区，通过牛角岭关城，到落坡马志远故居，然后经韭园桥沿永定河谷至担礼大桥进入G109。&lt;/p&gt;
&lt;p&gt;京西古道风景区收20￥，里面有博物馆、军事酒吧、古道和牛角岭关城。博物馆其实就是个村史展馆，很小，没什么内容，就一间屋子，一览无余。古道是乱石砌成的，非常不平，推车上去很累，好在只有一千米长：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CS026ew0/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;牛角岭关城，看著像个砖窑，地上的石头沟沟坎坎：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CS024QNx/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;马志远故居，看著像重建的，刻意营造成“小桥流水人家”的样子，里面就一四合院，收费10￥，没进去。附近有一山泉，想老马也算过了一把农妇山泉有点儿田的瘾，夫复何求。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CS024f86/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;永定河谷一线的景色非常好，可惜没有拍照。&lt;/p&gt;</description></item><item><title>解决ROX-Filer文件类型识别问题</title><link>http://0x3f.org/posts/fix-ms-office-mime-types-in-rox-filer/</link><pubDate>Fri, 17 May 2013 12:52:00 +0000</pubDate><guid>http://0x3f.org/posts/fix-ms-office-mime-types-in-rox-filer/</guid><description>&lt;p&gt;默认情况下，ROX-Filer会将“*.docx”、“*.xlsx”、“*.pptx”文档识别为zip压缩包。由于ROX中与文件关联的行为实际上都是和文档类型挂钩的，所以对这些文档的操作会遇到很大麻烦，而且没有变通方法。&lt;/p&gt;
&lt;p&gt;实际上，Linux对文件类型的识别比Windows灵活。Windows只能通过文件名的后缀判断文件类型，随便创建一个文本文件，然后将后缀“.txt”改成“.exe”，Win就会傻乎乎地认为这是个二进制的可执行程序。这种做法很傻，而且很不安全，试想，如果将一个病毒程序的后缀改成“.jpg”，就可以骗过大多数用户，然后通过某种手段执行它，后果会怎样？更傻的是，XP以上版本默认是隐藏后缀的，那攻击者连改后缀都可以省了。颤抖吧，神一样的Win！&lt;/p&gt;
&lt;p&gt;Linux不但可以通过后缀识别文件类型，更重要的，还可以通过文件开头的几个字节实现这一点，这就比前一种方式精确、安全很多。当然，Linux还支持更多的文件类型识别方法。&lt;/p&gt;
&lt;p&gt;前面说过，在ROX-Filer下，所有行为都绑定到文件类型上，也就是MIME Types，ROX通过这种方式实现了将可灵活自由定制的文件操作与自身解耦，从而在确保自身稳定的同时实现对高度灵活的自由定制的支持，这是一个很值得学习的实现方式。因此，既然文件的后缀没有问题，ROX仍将它们识别为ZIP格式，原因是什么？显然，最大的嫌疑集中在第二种识别方式上。&lt;/p&gt;
&lt;p&gt;一个公开的秘密是，Office文档本身其实就是一个ZIP压缩包，里面包含了描述文档的XML、多媒体文件等成分，只不过MS贱贱地把压缩包的后缀改成了docx之类的东东，加上Windows只能通过后缀识别文件类型，所以很多人不知道这一点。了解了这个，问题的原因就跃然纸上了，既然都是ZIP压缩包，那第二种文件类型识别方式也就区分不出Office文件类型与ZIP压缩包了。&lt;/p&gt;
&lt;p&gt;能号出病因，就有方子治病。&lt;/p&gt;
&lt;p&gt;既然ROX使用多种文件类型识别方式，那必然有一个优先级的关系，否则就会乱套。打开ROX的MIME Editor：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRNkfq0g/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;找到MIME类型“application/zip”：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRNkgaEK/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;打开zip的属性对话框：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRNkfOsQ/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;可以看到“Contents matching”这一块里，通过检查文件头部的几个字节是否为“PK\003\004”来判断，并且此项判断标准的优先级是40。下面所要做的，就是找到相应文件类型，添加一项条件相同的“Contents matching”，并把优先级设得大于40。&lt;/p&gt;</description></item><item><title>乐山大佛与十面普贤</title><link>http://0x3f.org/posts/tour-to-leshan-and-emei/</link><pubDate>Thu, 16 May 2013 22:04:00 +0000</pubDate><guid>http://0x3f.org/posts/tour-to-leshan-and-emei/</guid><description>&lt;p&gt;12年8月，去乐山、峨嵋玩儿了两天。&lt;/p&gt;
&lt;p&gt;乐山大佛真的很大：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRHkdf2T/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;据说佛爷头上的便便越多，表示智慧越大、级别越高：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRHkdm6f/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;峨嵋金顶的十面普贤菩萨，美轮美奂，从没有见过这样一尊佛像，能让人在看第一眼的时候就感受到震撼：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRHkdPGq/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;云开日出时的十面普贤，那一瞬间，场面无以言表，极为震撼人心：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRHkexyO/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;刚到乐山时看到路边的条幅，才恍然想起这是祖师爷的老家，没时间拜谒，罪过罪过。这次旅行最大的收获就是看到了云开日出时的十面普贤，是我迄今见过的最摄人心魄的景观。&lt;/p&gt;</description></item><item><title>夜爬百望山</title><link>http://0x3f.org/posts/nightly-climbing-baiwang-mountain/</link><pubDate>Wed, 15 May 2013 22:51:00 +0000</pubDate><guid>http://0x3f.org/posts/nightly-climbing-baiwang-mountain/</guid><description>&lt;p&gt;今晚参加了绿野夜爬百望山的活动。主要为了认一下路，以前逃票都是从公路旁栅栏的缺口钻进去的，后来封了就没再去。&lt;/p&gt;
&lt;p&gt;站在望京楼上俯瞰夜色中的帝都：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRxZLvnf/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;活动强度很低，适合下班后锻炼一下。百望山很矮，但是叉路很多，有的爬了。&lt;/p&gt;</description></item><item><title>五一徒步恒山、云冈石窟</title><link>http://0x3f.org/posts/tour-to-hengshan-and-yungang/</link><pubDate>Mon, 13 May 2013 22:48:00 +0000</pubDate><guid>http://0x3f.org/posts/tour-to-hengshan-and-yungang/</guid><description>&lt;p&gt;绿野的活动。&lt;/p&gt;
&lt;p&gt;头天晚上的汽车，第二天早上三四点到恒山后山，五点出发。很冷，除了T恤，就穿了一件冲锋衣，冻得直哆嗦，不过一开始爬就好多了。上山的地方不知名，不是传说中的后山山门附近。爬上第一个山顶，转过去就是修好的登山道，放眼可见莽原与群山：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYJnD5/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;底下就是我们当晚要宿营的恒山湖：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoY6mqe/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;朕与江山：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYL2y8/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;再往上没多远就是山顶，恒山海拔虽高，实际爬起来难度很低。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoY7nK3/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;都说前山景色一般、精华在后山，没感觉，也许跟我们走的路线有关，倒觉得前山附崖而建的寺庙耐看：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYLtQX/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;逢山必看摩崖石刻：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYLZh3/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;前山处处隐没在山林中的寺庙，很有意境：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYN4k9/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;边下边逛，中午就下了山，不明白这么一座平平无奇的山怎么称得上北岳恒宗：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYNuyE/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;然后坐车去悬空寺，寺小、人多、票贵，没上去，远远地拍上几张交作业：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYNRPW/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;不宿营的人坐车去浑源县城住宿，我们徒步走回恒山湖扎营。湖并不好看，水也不怎么干净，有人钓鱼，空手而归，好在湖边有小饭馆，好吃就别想了，聊胜于无。扎营地是山脚一个凹口，是片干了的湖底，没草，所以帐蓬容易进灰而且硌得慌，远不像想像中青山绿水草地上伴著明月篝火清风入睡那样享受。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYbD6g/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYQ2bn/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;虽然没有鱼，篝火还是要有的：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRfxM4Tt/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;除了被冻醒一次，一夜无话。第二天早上坐车去浑源县城吃传说中的小媳妇凉粉，这个地方的凉粉配料有特色，主要有三样东西：不辣的辣椒油、豆干和炸蚕豆，而作为主料的凉粉本身却并不比其它地方的特别，我想像中好的凉粉应该是入口即化的。不管怎样，有这样的经历也是好的：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYPP7x/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;然后坐车去云冈石窟，首先进去是灵严寺：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYQvF7/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;灵严寺的塔和佛像都很有特色，不著重彩，呈乳白色或米黄色，观感素雅：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYQYOZ/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYTaPo/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;双层建筑在我到过的寺庙里是第一次见到：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYejCS/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;大雄宝殿门口的黄金树很耀眼：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYSJjP/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYTxWt/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;寺后就是云冈石窟，风化的石壁很有沧桑感，与前面金碧辉煌的灵严寺对比鲜明。最近越来越不喜欢破败的事物，所以在前面寺庙的兴致至此稍挫：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYU1AP/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;大窟中的巨佛，依稀可见鲜卑帝国时代的盛况：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYUUrh/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYW8Is/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;石窟的外部原本都是有附崖建筑的：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CPoYVmSI/medium.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;下午四点，坐车返京，晚上九点左右抵西直门散伙。&lt;/p&gt;
&lt;p&gt;活动贴在这里：http://bbs.lvye.cn/thread-780144-1-1.html&lt;/p&gt;
&lt;p&gt;最后是恒顶合影：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CRyeLPEh/medium.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>博主本紀</title><link>http://0x3f.org/about/</link><pubDate>Sun, 12 May 2013 20:46:00 +0000</pubDate><guid>http://0x3f.org/about/</guid><description>&lt;p&gt;博主者，故陳國人也，起於閭左，姓名不可考。&lt;/p&gt;
&lt;p&gt;少有痴名，喜讀書，涉獵頗雜，不求甚解。弱冠之年，游學淮左，無所成。及長，愈癲痴無知、憊懶無賴。時有西域番國進貢算籌之機，以雷公電母之力驅使，天朝善之，百業咸用，遂渾跡帝都，以操機佐餌。幸天資未泯，頗悉C、PHP、Java、Javascript、Python、Lua、Bash等西域奇技淫巧，尤善Linux、Vim等奇門遁甲之術。以文明之興，皆由主義，遂奉李查德·斯托曼及李納斯·托瓦茲為二聖，厲行KISS、DRY諸原則。&lt;/p&gt;
&lt;p&gt;於他事皆甚愚鈍。雖標榜中右政治傾向，然實不聞國事。裹腹之余，唯以晴耕雨讀寄意，喜山水，樂遊歷，以太白「五嶽尋仙不辭遠，一生好入名山游」自命。&lt;/p&gt;
&lt;p&gt;偶一日，南柯一夢，為大司馬，大將軍，燕國公，領幽州牧，行驃騎大將軍事，冊拜太師、太傅、太保，假節鉞，受九錫，入朝不拜，過廷不趨，劍履上殿，贊拜不名，使持節、開府、儀同三司，都督冀、青、幽、並、兗、豫、梁、廣、揚九州諸軍事。大悅，為食斗粟。&lt;/p&gt;</description></item><item><title>读过Hello Android</title><link>http://0x3f.org/posts/after-reading-hello-android/</link><pubDate>Thu, 21 Feb 2013 21:01:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-hello-android/</guid><description>&lt;p&gt;春节前花了一周时间读完了这本书。&lt;/p&gt;
&lt;p&gt;是本不错的Android入门教材，能让人快速地搭出开发环境，了解Android应用的运作机制，对于移动应用开发的初学者尤其有用。当然，这种书一般不会讲得很全面，更深的东西还是要看官方文档，只是Android的官方指南写得比较散，并且过于简单，不适合初学者。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/CEUw95b5/gewxz.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>DualHead Watchdog v1.0 Released</title><link>http://0x3f.org/posts/dualhead-watchdog-v1-released/</link><pubDate>Sat, 16 Feb 2013 08:56:00 +0000</pubDate><guid>http://0x3f.org/posts/dualhead-watchdog-v1-released/</guid><description>&lt;p&gt;&lt;strong&gt;DualHead Watchdog&lt;/strong&gt; is a Linux desktop app which runs commands or scripts after display settings are changed.&lt;/p&gt;
&lt;p&gt;It is especially usefull for users who prefer window managers to those huge desktop environments. For these people, wallpapers often cannot be ajusted automatically when the screen size is changed or dual-head display is started. With this app, people can run custom commands to reset the background image when the display settings are changed.&lt;/p&gt;</description></item><item><title>迁移到 Octopress</title><link>http://0x3f.org/posts/migrate-blog-to-octopress/</link><pubDate>Sat, 23 Jun 2012 23:13:00 +0000</pubDate><guid>http://0x3f.org/posts/migrate-blog-to-octopress/</guid><description>&lt;h2 id="关于迁移"&gt;关于迁移&lt;/h2&gt;
&lt;p&gt;前段时间，用了五年的虚拟主机突然限制了PHP内存上限，导致Wordpress只能启用有限的几个插件，根本不能满足需要。&lt;/p&gt;
&lt;p&gt;所以毅然决定迁移到JeckyII+GitHub，在摸索的过程中发现octopress比JeckyII易用，于是导出所有文章，开始迁移。因为我这几年博客写得比较乱，无论是内容上，还是发表方式上，结果用了几个导出脚本，效果都不甚理想，还是有很多地方需要手工修改。六百篇文章，正好趁这个机会挑拣一下，较早的文章质量低的比较多。断断续续地迁移了一些，剩下的工作量还是很大的，留著以后慢慢来吧。另外这次把URL也改成永久格式了，这一来真的伤筋动骨了，连永久重定向都没的做。&lt;/p&gt;
&lt;p&gt;至于Feed输出，以前订阅Feedburner烧录的两个地址的读者不受影响，直接订阅Wordpress输出的地址的就丢了，这里再公布一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本博客聚合输出：http://feeds.feedburner.com/sinolog&lt;/li&gt;
&lt;li&gt;我的全部资讯聚合：http://feeds.feedburner.com/leninlee&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="迁移那点事"&gt;迁移那点事&lt;/h2&gt;
&lt;h3 id="python-版本的问题"&gt;Python 版本的问题&lt;/h3&gt;
&lt;p&gt;Archlinux很激进，早已把Python的缺省版本进化到了3.x，octopress会用到2.x，结果在生成全站的时候，会报如下错误：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; File &amp;#34;&amp;lt;string&amp;gt;&amp;#34;, line 1
import sys; print sys.executable
^
SyntaxError: invalid syntax
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在&lt;a href="http://blog.dayanjia.com/2012/04/fix-rubypython-bug-in-arch-linux/"&gt;这里&lt;/a&gt;找到解决方法。在octopress的plugins目录里创建文件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pygments&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="no"&gt;RUBY_PLATFORM&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;linux&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="no"&gt;RubyPython&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt; &lt;span class="ss"&gt;:python_exe&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/usr/bin/python2&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="不足"&gt;不足&lt;/h3&gt;
&lt;p&gt;用了这段时间octopress，感觉缺点也不小，每次修改后都要重新生成全站，占用系统资源不小，而且理论上以后会越来越慢。&lt;/p&gt;</description></item><item><title>读过"ZK: AJAX without the JavaScript Framework"</title><link>http://0x3f.org/posts/after-reading-zk-ajax-without-the-javascript-framework/</link><pubDate>Tue, 19 Jun 2012 21:47:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-zk-ajax-without-the-javascript-framework/</guid><description>&lt;p&gt;前段时间，某天凌晨无故醒来，读完了这本书。&lt;/p&gt;
&lt;p&gt;虽然是ZK框架的开发者写的书，不过实在不敢恭维。开发环境搭建的一章已经过时，其余内容也显得蜻蜓点水，加上全书结构显得不是很合理，总之看完对ZK的感觉仍是朦朦胧胧的，更别说上手做东西了。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.yupoo.com/photos/leninlee/85850069/" title="ZK: AJAX without the JavaScript Framework"&gt;&lt;img src="http://pic.yupoo.com/leninlee/C3luCjSG/medium.jpg" alt="ZK: AJAX without the JavaScript Framework" width="405" height="500" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>怎样为红帽系Linux发行版写系统服务脚本</title><link>http://0x3f.org/posts/how-to-write-service-scripts-for-redhat-distros/</link><pubDate>Tue, 19 Jun 2012 00:14:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-write-service-scripts-for-redhat-distros/</guid><description>&lt;p&gt;##阅读说明&lt;/p&gt;
&lt;p&gt;阅读本文要求有基本的Linux系统使用经验和Bash脚本编程能力。&lt;/p&gt;
&lt;p&gt;本文所述的内容适用于RHEL、CentOS等红帽系Linux发行版。&lt;/p&gt;
&lt;p&gt;##系统服务简介&lt;/p&gt;
&lt;p&gt;###常用命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 启动MySQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service mysqld start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 关闭MySQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service mysqld stop
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 重启MySQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service mysqld restart
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 查看MySQL服务运行状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service mysqld status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 查看MySQL服务是否开机自动运行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chkconfig --list mysqld
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 设置MySQL服务开机自动运行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chkconfig --level &lt;span class="m"&gt;345&lt;/span&gt; mysqld on
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 取消MySQL服务开机自动运行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chkconfig --level &lt;span class="m"&gt;345&lt;/span&gt; mysqld off
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;###运行级别&lt;/p&gt;</description></item><item><title>读完《三体——死神永生》</title><link>http://0x3f.org/posts/after-reading-three-body-long-live-the-king-of-terrors/</link><pubDate>Thu, 14 Jun 2012 22:20:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-three-body-long-live-the-king-of-terrors/</guid><description>&lt;p&gt;前天夜里读完了《三体》的第三部。&lt;/p&gt;
&lt;p&gt;这三部一部比一部成熟。第一部只能算是整个故事的开端；第二部的亮点在最后揭示黑暗森林，前面的部分废话太多；第三部开始出现情节的跌宕，是三部中最像小说的一部。&lt;/p&gt;
&lt;p&gt;诚如所闻，刘慈欣真的把地球写毁灭了。但是站在宇宙众生的角度冷眼旁观要好过以人类自我为中心的意淫，边泡妞边救地球的好莱坞套路也就是过过眼瘾而已。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.yupoo.com/photos/leninlee/85808819/" title="三体3死神永生"&gt;&lt;img src="http://pic.yupoo.com/leninlee/C2AFUunY/medium.jpg" alt="三体3死神永生" width="340" height="500" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>读完《三体——黑暗森林》</title><link>http://0x3f.org/posts/after-reading-three-body-the-dark-forests/</link><pubDate>Tue, 01 May 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-three-body-the-dark-forests/</guid><description>&lt;p&gt;凌晨三点，读完了《三体》的第二部。&lt;/p&gt;
&lt;p&gt;咒语，这个东西的确很有意思。第二部比第一部好看，故事情节上完全展开，成功地制造了悬念。如果一部小说，删掉很多文字仍不影响故事情节，那这部分就是多余的，可惜在这部书里这是个很大的问题，所以直到最后三分之一才真正出彩。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/tt1qOjDU6_6tnnQgdfYtw9MTjNZETYmyPJy0liipFm0?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-OcSgdVvYZD8/T57gVJYqtyI/AAAAAAAAB4E/C6tOtnZPX28/s800/s4700425.jpg" height="426" width="312" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>UltraBlog.vim v3.5.0: 内建浏览器</title><link>http://0x3f.org/posts/ultrablog-v350-released/</link><pubDate>Mon, 30 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-v350-released/</guid><description>&lt;p&gt;此前预览文章是通过调用系统默认的网络浏览器实现的，缺点是这些功能完备的浏览器启动速度不甚理想，尤其是火狐，谁用谁知道。&lt;/p&gt;
&lt;p&gt;前两天看了TuxRadar的一个Podcast，几分钟内就可以用pywebkitgtk拼装出一个五脏俱全的网络浏览器，pywebkitgtk这个东西实在是非常的好用。不过我实测后发现这东西加载页面的速度比较慢，而且貌似是单线程的，因为图片都是放在最后才加载，不知道是这个绑定本身的问题，还是有API可以实现的。于是突然想到拿这个东西实现一个简单的浏览器，很适合在UB里预览文章。&lt;/p&gt;
&lt;p&gt;增加了一个选项&lt;strong&gt;“ub_use_ubviewer”&lt;/strong&gt;，默认值是1，即默认使用这个内建的浏览器预览文章。当这个选项的值被设为0时，仍然使用系统的默认浏览器，并且在Vim启动时不会加载内建的浏览器。这样做一是为了多一种选择，再一个也可以避开烦人的GTK警告：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;** (gvim:13629): WARNING **: Trying to register gtype 'GMountMountFlags' as enum when in fact it is of type 'GFlags'&lt;/p&gt;
&lt;p&gt;** (gvim:13629): WARNING **: Trying to register gtype 'GDriveStartFlags' as enum when in fact it is of type 'GFlags'&lt;/p&gt;
&lt;p&gt;** (gvim:13629): WARNING **: Trying to register gtype 'GSocketMsgFlags' as enum when in fact it is of type 'GFlags'&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这些警告是GTK或其它一些程序库的Bug造成的，虽然只在虚拟终端中启动Vim时会显示并且不影响使用，但总会有警告恐惧症患者会觉得这种东西很闹心。如果这样，就把这个选项的值设成0，用回巨型浏览器好了。&lt;/p&gt;
&lt;p&gt;本次更新的全部内容如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Feature: Add a tiny web browser to do previewing, which starts much faster than full-functional browsers like firefox and chromium. The later ones are still supported. The matter that whether or not to use the new previewer is controlled by a new option &lt;strong&gt;ub_use_ubviewer&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Bugfix: Issue 7: Keywords highlighting is disabled in item lists, even if searches are made manually.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于UB的详细信息在&lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;这里&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>UltraBlog.vim v3.4.0: 正则表达式、批量替换和调试模式</title><link>http://0x3f.org/posts/ultrablog-v340-released/</link><pubDate>Sun, 29 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-v340-released/</guid><description>&lt;p&gt;这次的更新主要引入了支持正则表达式的全文检索、批量替换和调试模式。&lt;/p&gt;
&lt;h2&gt;正则表达式&lt;/h2&gt;
&lt;p&gt;我一直觉得原来的全文检索有一个遗憾，虽然可以通过多个关键词实现较为精确的查询，但还是不如正则表达式灵活和精确。&lt;/p&gt;
&lt;p&gt;这是个蓄谋已久的需求，但直到真正做起来，才发现很多有意思的东西。虽然SQLite3提供支持正则表达式查询的&lt;strong&gt;“REGEX”&lt;/strong&gt;关键词，但并没有实际实现这个功能，而是需要写程序实现并在数据库接口中注册这个函数：&lt;/p&gt;
```python
import sqlite3
conn = sqlite3.connect('/tmp/your-database-file.db')
# 使用正则表达式匹配给定内容的函数，返回布尔类型
def regexp_search(expr, item):
"""Check if the item has a sub-string which matches the expr"""
reg = re.compile(expr)
return reg.search(item) is not None
# 在数据库中注册这个函数
conn.create_function('REGEXP', 2, regexp_search)
cur = conn.execute('select id,title from post where content REGEXP ?', '\babc\b')
row = cur.fetchone()
print row
conn.close()
```
&lt;p&gt;在SQLAlchemy中具体的实现方式是：&lt;/p&gt;
```python
# 注册函数
dbe = sqlalchemy.create_engine("sqlite:///tmp/your-database-file.db")
conn = dbe.connect()
conn.connection.create_function('REGEXP', 2, regexp_search)
# 在SQL Expression Language中创建查询条件
tbl = Post.__table__
cond_1 = tbl.c.title.op('regexp')(r'\babc\b')
cond_2 = tbl.c.content.op('regexp')(r'\babc\b')
```
&lt;p&gt;和普通的全文检索一样，正则表达式的全文检索也支持使用多个表达式作为查询条件，多个条件之间是与的关系。现在可以这样查询所有包含“UltraBlog.vim”但不把推广代码算在内的文章了：&lt;/p&gt;</description></item><item><title>PHP大量常量应集中使用APC定义</title><link>http://0x3f.org/posts/define-massive-constants-using-apc/</link><pubDate>Tue, 24 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/define-massive-constants-using-apc/</guid><description>&lt;p&gt;用xdebug跟踪程序性能时，发现一个定义了约七百个常量的文件，include_once()时消耗约六十毫秒的时间。事实上define()的效率比较低，如果需要定义大量常量，使用APC扩展提供的apc_define_constants()效果会好得多。&lt;/p&gt;
&lt;p&gt;下面是对这个文件改造前后效率跟踪结果的对比：&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;define()方案（ms）&lt;/th&gt;
&lt;th&gt;apc_define_constants()方案（ms）&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;启动Web服务和PHP，第一次运行&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;不重启Web服务和PHP，第二次运行&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;不重启Web服务和PHP，第三次运行&lt;/td&gt;
&lt;td&gt;66&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;由此可见，apc_define_constants()不但在初次调用时效能就超过define()，而且由于APC自身的缓存功能，在后续调用时效率会有进一步的提高，而define()基本没有变化。&lt;/p&gt;
&lt;p&gt;以下是apc_define_constants()的代码示例：&lt;/p&gt;
```php
&lt;?php
if(!apc_load_constants('my_constants')) {
$constants = array(
'ONE' =&gt; 1,
'TWO' =&gt; 2,
'THREE' =&gt; 3,
);
apc_define_constants('my_constants', $constants);
}
?&gt;
```
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>慎用PHP的fsockopen()连接localhost</title><link>http://0x3f.org/posts/fsockopen-fails-connecting-localhost/</link><pubDate>Tue, 24 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/fsockopen-fails-connecting-localhost/</guid><description>&lt;p&gt;使用xdebug跟踪程序性能时发现fsockopen()函数耗时一秒，单步调试发现实际在这里超时了，而超时时间设置的就是一秒。&lt;/p&gt;
&lt;p&gt;如果把目标地址由原来的“localhost”换成“127.0.0.1”，马上就可以连上。在PHP的Bug跟踪系统中找到这个问题：&lt;/p&gt;
&lt;p&gt;https://bugs.php.net/bug.php?id=50953&lt;/p&gt;
&lt;p&gt;看起来像是在5.2.12以后已修改，但我发现在5.2.17中仍存在这个问题。另有说法在5.3中不存在这个问题，我没有测试。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>UltraBlog.vim v3.3.0：I18N、超时时间和其它</title><link>http://0x3f.org/posts/ultrablog-v330-released/</link><pubDate>Sun, 15 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-v330-released/</guid><description>&lt;p&gt;UB一岁了，这算是个周年纪念版吧。&lt;/p&gt;
&lt;p&gt;在这一年里，因为各种原因，博客写得没有以前多了，但每篇都是用这个插件写的，我觉得很好用。断断续续地做了一些修改，因为一切都是一个人在做，所以大的变化不多。这次这个版本里有些改动还是要感谢&lt;a href="http://ihacklog.com/"&gt;荒野无灯&lt;/a&gt;童鞋，他的&lt;a href="https://github.com/xbot/UltraBlog.vim/issues/3"&gt;建议&lt;/a&gt;很大程度上催生了这个新版本：比如加入保存命令的热键映射选项，这样可以使用保存普通文件的热键保存UB中的内容，我自己以前也经常习惯性地用错热键；还有socket超时时间的选项，最近我这里也经常性地在UB操作博客时报超时的异常，荒童鞋关于自定义socket超时时间的建议一语惊醒了梦中人。&lt;/p&gt;
&lt;p&gt;此外，似乎与近期Vim的一次升级&lt;a href="http://comments.gmane.org/gmane.editors.vim.devel/34092"&gt;有关&lt;/a&gt;，在Vim中调用Python接口打印任何内容到标准IO都会导致Vim崩溃，所以这次把所有的输出都改成了调用Vim的输出命令来做。&lt;/p&gt;
&lt;p&gt;本次修改的内容中，还有一项比较重要的内容就是实现了国际化，目前只提供英文和简体中文两种语言，由于Vimball不能处理二进制文件，所以从此以后UB改用zip格式压缩包打包。&lt;/p&gt;
&lt;p&gt;以下是本次更新的详细内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Feature: Add i18n support !&lt;/li&gt;
&lt;li&gt;Feature: Add a new option &lt;strong&gt;ub_hotkey_save_current_item&lt;/strong&gt;, users can define their own hotkey for &lt;strong&gt;:UBSave&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Feature: Add a new option &lt;strong&gt;ub_socket_timeout&lt;/strong&gt;, users can customize the timeout period in seconds, useful for slow networks.&lt;/li&gt;
&lt;li&gt;Bugfix: Exception raised when one event is processed by more than one event handlers.&lt;/li&gt;
&lt;li&gt;Change: Echoing messages now uses the command :echoerr instead of python's sys.stderr, because Vim crashes on this due to an upgrade recently.&lt;/li&gt;
&lt;li&gt;Change: Change commands &lt;strong&gt;:UBSave&lt;/strong&gt;, &lt;strong&gt;:UBSend&lt;/strong&gt;, &lt;strong&gt;:UBUpload&lt;/strong&gt;, &lt;strong&gt;:UBConv&lt;/strong&gt;, &lt;strong&gt;:UBPreview&lt;/strong&gt; to be available only in their effective views.&lt;/li&gt;
&lt;li&gt;Change: Lists are set nowrapped.&lt;/li&gt;
&lt;li&gt;Bugfix: Stop complaining '&lt;strong&gt;_pop from empty list_&lt;/strong&gt;' while doing almost everything.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于UB的详细信息在&lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;这里&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>在Archlinux下使用thinkfan控制Thinkpad x220的风扇转速</title><link>http://0x3f.org/posts/how-to-control-fan-speed-with-thinkfan/</link><pubDate>Sat, 14 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-control-fan-speed-with-thinkfan/</guid><description>&lt;p&gt;Archlinux目前对Thinkpad风扇的自动控制效果并不好，气温上升后很容易出现一直在三千多转一直跑的问题。thinkfan是目前用的比较多的自动控制风扇转速的程序，但Google到的配置thinkfan的文章大多语焉不详，可能是跟具体的发行版有关，因为貌似有些发行版中安装了thinkfan后会自动生成缺省的配置文件，但在目前的AUR中的包被安装后却没有生成任何配置文件。&lt;/p&gt;
&lt;p&gt;下面是我在Archlinux下配置的步骤，实际效果很好，现在只要不看视频、不编译程序、不启动Chromium，一般是两千九百转的速度，安静多了。&lt;/p&gt;
&lt;h2&gt;lm_sensors&lt;/h2&gt;
&lt;p&gt;安装lm_sensors并执行命令初始化：&lt;/p&gt;
```bash
# 一路回车
sudo sensors-detect
```
&lt;p&gt;将sensors加入rc.conf中DAEMONS中，开机启动。&lt;/p&gt;
&lt;p&gt;启动sensors服务：&lt;/p&gt;
```bash
sudo rc.d start sensors
```
&lt;h2&gt;thinkpad_acpi&lt;/h2&gt;
&lt;p&gt;修改文件“&lt;strong&gt;/etc/modprobe.d/thinkpad_acpi.conf&lt;/strong&gt;”：&lt;/p&gt;
```
options thinkpad_acpi fan_control=1
```
&lt;p&gt;我这里虽没有把thinkpad_acpi加到rc.conf的MODULES中，但lsmod也是可以看到它的，说明还是自动启用了。要使上面这项配置生效，必须重启电脑，我这里重启thinkpad_acpi模块时报错说该模块正在被使用。&lt;/p&gt;
&lt;h2&gt;thinkfan&lt;/h2&gt;
&lt;p&gt;安装thinkfan并修改文件“&lt;strong&gt;/etc/default/thinkfan&lt;/strong&gt;”：&lt;/p&gt;
```
START=yes
```
&lt;p&gt;修改文件“&lt;strong&gt;/etc/thinkfan.conf&lt;/strong&gt;”：&lt;/p&gt;
```
sensor /sys/class/hwmon/hwmon0/temp1_input
(0, 0, 55)
(1, 48, 60)
(2, 50, 61)
(3, 52, 63)
(4, 56, 65)
(5, 59, 66)
(7, 63, 32767)
```
&lt;p&gt;将thinkfan加入rc.conf的DAEMONS中，开机自动启动。&lt;/p&gt;
&lt;p&gt;启动thinkfan：&lt;/p&gt;
```bash
sudo thinkfan
```
&lt;h2&gt;查看状态&lt;/h2&gt;
```bash
# 看CPU温度和风扇转速
sensors
# 看风扇详细信息
cat /proc/acpi/ibm/fan
```
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>TurboCRM Cluster Express v1.0 释出</title><link>http://0x3f.org/posts/turbocrm-cluster-express-v1-released/</link><pubDate>Sun, 08 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/turbocrm-cluster-express-v1-released/</guid><description>&lt;p&gt;TurboCRM Cluster Express是TurboCRM的集群实施工具。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://pic.yupoo.com/leninlee/BSfJUW1x/medium.jpg" alt="illustration" /&gt;&lt;/p&gt;
&lt;p&gt;去年我曾经写过一个配置集群的Bash脚本“cluster.sh”，TCE是对这个脚本的图形界面封装，通过可视化的操作简化集群的实施工作。&lt;/p&gt;
&lt;p&gt;TCE的最新版本和使用说明可以在&lt;a href="http://xbot.github.com/TurboCRM-Cluster-Express/"&gt;这里&lt;/a&gt;找到。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>禁止屏幕在播放视频时自动关闭</title><link>http://0x3f.org/posts/how-to-keep-monitor-active-while-watching-flv/</link><pubDate>Wed, 04 Apr 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-keep-monitor-active-while-watching-flv/</guid><description>&lt;p&gt;貌似Lose系统下看在线视频的时候不会超时自动关闭屏幕，但是我在Arch下就一直晃鼠标、按键盘来著，这严重违反了DRY原则。于是昨天终于写了这个脚本，当全屏播放视频的时候，关闭屏保和显示器的节能特性，否则则激活它们。由于是在X的级别实现，理论上应当适合所有桌面环境。&lt;/p&gt;
```bash
#!/bin/bash
# Baby-sitter of the monitor's DPMS
idle_period=60
ss_switch_off=0
ss_is_off=0
while true; do
# Read DPMS state
xset -q|grep "DPMS is Disabled" &gt; /dev/null &amp;&amp; ss_is_off=1 || ss_is_off=0
# Get pid of the current window
active_window_id=`xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)" | cut -d" " -f5`
decimal_id=`xprop -id $active_window_id | grep PID | cut -d" " -f3`
# Traverse all libflashplayer.so
for pid in `ps -ef|grep -v grep|grep libflashplayer.so|awk '{print $2}'`; do
# If the current window is libflashplayer.so
if [ "$pid" -eq "$decimal_id" ]; then
ss_switch_off=1
break
else
ss_switch_off=0
fi
done
if [ $ss_switch_off -eq 1 ]; then
# Turn off DPMS
echo Turn off DPMS
if [ $ss_is_off -eq 0 ]; then
echo Action
xset s off
xset -dpms
fi
else
# Turn on DPMS
echo Turn on DPMS
if [ $ss_is_off -eq 1 ]; then
echo Action
xset +dpms
xset s on
fi
fi
sleep $idle_period
done
```
&lt;p&gt;似乎对非全屏播放的情况没有什么好方法。&lt;/p&gt;</description></item><item><title>关于PyGTK.CellRenderer的回调方法中聚焦异常的问题</title><link>http://0x3f.org/posts/the-focus-issue-of-pygtk-cellrenderer/</link><pubDate>Sun, 25 Mar 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/the-focus-issue-of-pygtk-cellrenderer/</guid><description>&lt;p&gt;遇到这样一个问题：&lt;/p&gt;
&lt;p&gt;在pygtk.TreeView中，需要在一个Cell的值被修改后做一个校验，如果不合法，则重新聚焦该Cell并选中其中的内容。&lt;/p&gt;
&lt;p&gt;示意代码如下：&lt;/p&gt;
```python
# pygtk.CellRenderer的edited事件的回调方法
def onCellEdited(self, cell, path, newText, userData):
store,colNum = userData
# 使用事件驱动的设计理念，创建一个自定义的事件
evt = ServerTypeChangedEvent(self, cell, usrData)
# 事件入队列
EventQueue.fireEvent(evt)
# 处理事件队列，如果截获异常，提示并重新聚焦Cell
try:
EventQueue.processEvents()
except Exception,e:
self.alert(e.message)
col = self.treeView.get_column(colNum-1)
# 聚焦Cell，并选中Cell中的内容
self.treeView.set_cursor_on_cell(path, col, cell, True)
```
&lt;p&gt;关键的代码在最后一行，通过调用TreeView的set_cursor_on_cell方法聚焦Cell并选中其内容。但就是这一步出了问题，报如下警告：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GtkWarning: _gtk_tree_view_column_start_editing: assertion `tree_column-&gt;editable_widget == NULL' failed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;此后整个TreeView的行为表现不正常，表现为可直接修改其它Cell的内容，且原Cell一直处于聚焦状态。&lt;/p&gt;
&lt;p&gt;此问题的原因是：edited事件在Cell的输入控件被销毁前就发出了，这时在事件的回调方法中重新聚焦该Cell就导致了这个问题（&lt;em&gt;详见&lt;a href="http://www.gtkforums.com/viewtopic.php?t=4619"&gt;这里&lt;/a&gt;&lt;/em&gt;）。&lt;/p&gt;
&lt;p&gt;解决方法是借助glib.idle_add函数，在PyGTK空闲的时候再调用set_cursor_on_cell方法，由于此时原控件已被销毁，所以不会有问题。&lt;/p&gt;
&lt;p&gt;修改后的代码如下：&lt;/p&gt;
```python
def onCellEdited(self, cell, path, newText, userData):
store,colNum = userData
evt = ServerTypeChangedEvent(self, cell, usrData)
EventQueue.fireEvent(evt)
try:
EventQueue.processEvents()
except Exception,e:
self.alert(e.message)
col = self.treeView.get_column(colNum-1)
#self.treeView.set_cursor_on_cell(path, col, cell, True)
import glib
glib.idle_add(self.treeView.set_cursor_on_cell, path, col, cell, True)
```
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Mac，江湖再见！</title><link>http://0x3f.org/posts/bye-mac/</link><pubDate>Mon, 12 Mar 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/bye-mac/</guid><description>&lt;p&gt;零八年底，我用半年的差补收了当时Thinkpad X200顶配的FN3。三年的时间，几乎每天都要用很久，竟然从没掉过链子。虽说是这样，但毕竟用的强度大、时间长，屏幕已经远不如当初清晰，亮度也差了，即使调到最高亮度都觉著暗。&lt;/p&gt;
&lt;p&gt;于是打算趁著还能发挥余热，趁早处理掉，省得将来砸手里。&lt;/p&gt;
&lt;p&gt;既然要换，不如玩儿得折腾一点儿，于是小手一抖，Mac到手。&lt;/p&gt;
&lt;p&gt;我对Mac的OS只是有点小好奇，主要是奔著Mac的外观和做工去的，还是打算回头装Arch。玩儿了四个月，平心而论，Mac OS X确实是个不错的OS，美观程度无与伦比，结合Mac硬件的外观和做工，真是天作之合；易用性之高，确实让我有点小惊讶，多点触摸得心应手，软件安装一拖而就，相比之下，Windows显得拙劣不堪。&lt;/p&gt;
&lt;p&gt;如果只是作为办公和娱乐的工具，Mac可挑剔的地方确实不多。但是易用性往往和灵活性成反比，灵活性高意味著你可以随心所欲地制定自己的游戏规则，而易用性高则往往意味著你只能接受它的方式、认可它的价值观，易用并不代表顺手。&lt;/p&gt;
&lt;p&gt;除此之外就是软件资源的问题，Mac的免费软件相对很少，而且和Windows一样，需要先下载，再安装。虽然也有MacPorts、Homebrew，和Linux的软件仓库比起来还是差得太远。&lt;/p&gt;
&lt;p&gt;做惯了Archer，是可忍，孰不可忍。&lt;/p&gt;
&lt;p&gt;还是要装Arch。但是在制作安装介质这一步就遇著麻烦了，USB启动安装盘死活都不认，试了几种方法，无果。此外还有不少未知的问题，比如驱动等等。&lt;/p&gt;
&lt;p&gt;如果在几年前，在学校，有大把的时间可以糟蹋，我就跟丫死掐了。现在不行了，伤不起了。果断入手Thinkpad X220 A45，上周六把Mac出手了。&lt;/p&gt;
&lt;p&gt;小黑和Arch不愧是天作之合，比起当初在X200上装的时候还容易。只是小黑的多点触摸板啊，东施效颦，我想不到更贴切的词形容了，太TMD坑爹了！&lt;/p&gt;
&lt;p&gt;鉴于X200上4G内存被Chromium吃光光的苦逼经历，这次果断入手两根4G的三星金条，都是党的政策好啊，最近内存白菜价，两根金条才300粮票。&lt;/p&gt;
&lt;p&gt;从宣和八年秋十月到宣和九年春王三月，我的短暂的小白史告一段落，MacBook Pro MC700CH/A，江湖再见！&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>NGINX: 405 Not Allowed</title><link>http://0x3f.org/posts/nginx-405-not-allowed/</link><pubDate>Sun, 19 Feb 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/nginx-405-not-allowed/</guid><description>&lt;p&gt;NGINX不允许向静态文件提交POST方式的请求，否则报405错误。测试方法为，使用curl向服务器上的静态文件提交POST请求：&lt;/p&gt;
```bash
curl -d 1=1 http://localhost/version.txt
```
得到以下结果：
```html
&lt;html&gt;
&lt;head&gt;&lt;title&gt;405 Not Allowed&lt;/title&gt;&lt;/head&gt;
&lt;body bgcolor="white"&gt;
&lt;center&gt;&lt;h1&gt;405 Not Allowed&lt;/h1&gt;&lt;/center&gt;
&lt;hr&gt;&lt;center&gt;nginx/1.0.11&lt;/center&gt;
&lt;/body&gt;
&lt;/html&gt;
```
&lt;p&gt;网上传抄的添加以下配置的解决办法不可用：&lt;/p&gt;
```nginx
error_page 405 =200 @405;
location @405
{
root /srv/http;
}
```
&lt;p&gt;一种不完美但可用的方法为：&lt;/p&gt;
```nginx
upstream static_backend {
server localhost:80;
}
server {
listen 80;
# ...
error_page 405 =200 @405;
location @405 {
root /srv/http;
proxy_method GET;
proxy_pass http://static_backend;
}
}
```
&lt;p&gt;即转换静态文件接收的POST请求到GET方式。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>登入XFCE后自动关闭蓝牙的方法</title><link>http://0x3f.org/posts/how-to-disable-bluetooth-after-login-to-xfce/</link><pubDate>Sat, 18 Feb 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-disable-bluetooth-after-login-to-xfce/</guid><description>&lt;p&gt;Blueman不能记忆蓝牙的关闭状态，每次登入桌面都会自动打开蓝牙，既费电又不安全。&lt;/p&gt;
&lt;p&gt;一种方法是禁止bluetooth服务自动启动，缺点是使用蓝牙时不方便，还要手工启动bluetooth服务。&lt;/p&gt;
&lt;p&gt;另一种方法是登入桌面后自动关闭蓝牙，即使用如下命令：&lt;/p&gt;
```bash
sudo rfkill block bluetooth
```
&lt;p&gt;但XFCE不能定制自动启动程序的顺序，所以可以写下面这么个脚本，然后添加到自动启动程序列表中：&lt;/p&gt;
```bash
#!/bin/bash
blueman-applet &amp;
sleep 5
sudo rfkill block bluetooth
```
&lt;p&gt;当然，还要取消自动启动程序列表中原来的Blueman。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>启用新域名0x3f.org</title><link>http://0x3f.org/posts/enable-the-new-domain-name-0x3f-org/</link><pubDate>Mon, 09 Jan 2012 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/enable-the-new-domain-name-0x3f-org/</guid><description>&lt;p&gt;元旦假期第三天，还是把域名给换了。&lt;/p&gt;
&lt;p&gt;原因主要是.it太贵，年费十几刀，而.org只有它的一半。另外，原来的sinolog.it有点儿长，也显老气，想换个更个性、更短的。&lt;/p&gt;
&lt;p&gt;可惜中意的0xff有主了，只好退而求0x3f。0x3f在ASCII里面代表问号，象征“&lt;strong&gt;保持好奇心&lt;/strong&gt;”。&lt;/p&gt;
&lt;p&gt;按照&lt;a href="http://0x3f.org/?p=1356"&gt;上次&lt;/a&gt;的&lt;a href="http://0x3f.org/?p=1359"&gt;经验&lt;/a&gt;，对著数据库一通改，加上这两年四处沾花惹草，很多网站上的相关信息都得跟著改，长此以往，以后连域名都换不起了。&lt;/p&gt;
&lt;p&gt;好在RSS订阅早已经换成了FeedBurner烧录，只是对于直接用原域名订阅的需要改一下订阅地址了。&lt;/p&gt;
&lt;p&gt;用了几年国家域名，现在也用上国际域名了……&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>读完《三体》</title><link>http://0x3f.org/posts/after-reading-three-body/</link><pubDate>Sun, 18 Dec 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-three-body/</guid><description>&lt;p&gt;几年没读过小说了，上次读刘慈欣的《球状闪电》还是在学校的时候，多年后再次读小说的感觉怪怪的，有点陌生，也没有激情。虽然早就知道这部书，一直没看，现在终于利用零散时间在Kindle上读完了它。&lt;/p&gt;
&lt;p&gt;我不是个科幻迷，但也觉得这部书写得挺好。有悬念，立意新颖，尤其是据说在后两部里干脆把地球给写毁灭了！我要接著往下看。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/EIq6agpaM9dZfrvj5rJ6JtMTjNZETYmyPJy0liipFm0?feat=embedwebsite"&gt;&lt;img src="https://lh4.googleusercontent.com/-QJIQjYJ85sQ/Tu34YO-SubI/AAAAAAAAB2Y/AEZCJDQHzwA/s400/Threebody.jpg" height="400" width="277" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>读完《Hacking Vim7.2》</title><link>http://0x3f.org/posts/after-reading-hacking-vim72/</link><pubDate>Mon, 28 Nov 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-hacking-vim72/</guid><description>&lt;p&gt;作者对Vim很有心得，分享了很多好的经验。这本书于新手可以用来入门，于老手也多有可取之处，是本学习Vim很不错的参考书。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/EDVN2_nwQ4XWPoqe83VGpNMTjNZETYmyPJy0liipFm0?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-ezfYjiMqrrs/TtJnWRhKHzI/AAAAAAAAB14/hCidRx_DLj4/s400/cover.jpg" height="400" width="309" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>MatchTag.vim: 高亮配对的HTML标签</title><link>http://0x3f.org/posts/highlighting-paired-html-tags-using-matchtag-vim/</link><pubDate>Wed, 23 Nov 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/highlighting-paired-html-tags-using-matchtag-vim/</guid><description>&lt;p&gt;两年前我曾在&lt;a href="http://vim.1045645.n5.nabble.com/How-can-Vim-highlight-the-matching-tag-when-I-put-the-cursor-on-the-other-one-in-a-pair-of-tags-td1177554.html"&gt;Vim邮件列表&lt;/a&gt;里问怎样高亮配对的HTML标签，但没能解决。今天意外收到一封邮件，Linqq童鞋在&lt;a href="http://stackoverflow.com/questions/8168320/can-vim-highlight-matching-html-tags-like-notepad"&gt;StackOverflow&lt;/a&gt;上问了同样的问题，有人就写了这个&lt;a href="http://www.vim.org/scripts/script.php?script_id=3818"&gt;插件&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/wGB584-nLWrQRHCQ7qgADdMTjNZETYmyPJy0liipFm0?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/-ojoHK5ST944/Ts0QmwHOCXI/AAAAAAAAB1Q/ye0ko4Ob-gc/s800/2011-11-23.22%25253A40%25253A58.%2525E6%252593%2525B7%2525E5%25258F%252596%2525E9%252581%2525B8%2525E5%25258F%252596%2525E5%25258D%252580%2525E5%25259F%25259F.01.png" height="103" width="268" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>YYeTs.py：人人影视BT种子下载辅助脚本</title><link>http://0x3f.org/posts/yyets-torrents-download-script/</link><pubDate>Mon, 14 Nov 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/yyets-torrents-download-script/</guid><description>&lt;p&gt;这是最好的时代，这是最坏的时代。现在还有像&lt;a href="ftp://zhongzi.yyets.net"&gt;人人影视的BT种子FTP&lt;/a&gt;这样的站点，实在不容易。但是所有种子列在一块，想看看最近几天都更新了甚么都很困难，于是早想写个脚本省时省力。这周末终于实现了这个想法。&lt;/p&gt;
&lt;h2&gt;主要功能&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;按关键词查询种子&lt;/li&gt;
&lt;li&gt;限制查询范围为最近几天新增的&lt;/li&gt;
&lt;li&gt;下载符合查询条件的种子，允许下载前编辑任务列表&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;使用说明&lt;/h2&gt;
&lt;h3&gt;环境&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Python 2.7，不支持Python3&lt;/li&gt;
&lt;li&gt;Mac OS X Lion，Archlinux测试通过，理论上支持Windows&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;配置&lt;/h3&gt;
&lt;p&gt;如果需要编辑下载任务列表（&lt;em&gt;即使用-s选项&lt;/em&gt;），应事先配置环境变量&lt;strong&gt;YYETS_EDITOR&lt;/strong&gt;，将值设定为一个文本编辑器的路径，或者修改脚本的私有属性&lt;strong&gt;__editor__&lt;/strong&gt;也一样。如果这两个位置都没有设置，则使用环境变量&lt;strong&gt;EDITOR&lt;/strong&gt;。否则，将报“&lt;strong&gt;Command not found&lt;/strong&gt;”的错误。&lt;/p&gt;
&lt;p&gt;有一点提示，如果使用GVim或MacVim，需要加上选项&lt;strong&gt;-f&lt;/strong&gt;，以阻塞的方式启动它，否则会导致下载结果不能达到预期。例如对于MacVim，可配置&lt;strong&gt;YYETS_EDITOR&lt;/strong&gt;为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;mvim -f&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;使用举例&lt;/h3&gt;
```bash
# 列出所有种子
./yyets.py
# 搜索关键词
./yyets.py 猩球崛起 1080p
# 搜索最近三天新增的种子
./yyets.py --past=3
# 搜索最近七天内新增的、满足关键词条件的种子
./yyets.py --past=7 蓝精灵
# 下载满足查询条件的种子
./yyets.py -d --past=30 1080p
# 下载满足查询条件的种子，下载前编辑任务列表
./yyets.py -d -p --past=30 1080p
# 更多详细信息，参阅帮助
./yyets.py -h
./yyets.py --help
```
&lt;h3&gt;下载&lt;/h3&gt;
&lt;p&gt;移步GitHub获取最新版本：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/xbot/shell"&gt;https://github.com/xbot/shell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>读完《Pro Git》</title><link>http://0x3f.org/posts/after-reading-pro-git/</link><pubDate>Mon, 14 Nov 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-pro-git/</guid><description>&lt;p&gt;花了大约一周的时间，周日晚上读完&lt;a href="http://progit.org"&gt;《Pro Git》&lt;/a&gt;的最后几页。&lt;/p&gt;
&lt;p&gt;高效、安全的分布式和强大的分枝合并是Git的杀手级特性，这本书在语言上浅显易懂、简明扼要，在章节安排上循序渐进，在内容讲解上有较深入的挖掘，当属眼下Git方面最好的教材。此外，这本书的中译水平也很高，必要的地方还有译注，能看出译者不是外行。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/RuILnzirn3HwuJzk5Wp2Zw?feat=embedwebsite"&gt;&lt;img src="https://lh4.googleusercontent.com/-JaRvkCJzpFE/Tr_4ifkfXMI/AAAAAAAAB0w/K_4h24C2fis/s800/A9781430218333-3d_6.png" height="350" width="277" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>UltraBlog.vim v3.1释出：代码重构与MacVim支持</title><link>http://0x3f.org/posts/ultrablog-v310-released/</link><pubDate>Sat, 05 Nov 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-v310-released/</guid><description>&lt;p&gt;距离上一个版本的释出已经有三个月了，这次新版并没有增加多少功能性的内容，主要是代码的重构和对在MacVim下稳定性的改进。&lt;/p&gt;
&lt;p&gt;对依赖关系检查的不细致导致了一些麻烦，抛出的错误信息有时与实际原因相距甚远。由于开始时是以实现功能为主，所以都是直接用函数实现的，之后修修补补，代码冗余而且维护麻烦。于是著手重构主要功能的源码，面向对象，把所有检查逻辑放到父类中去实现，子类只关注自身逻辑，最后新版减少了二百多行的代码量。&lt;/p&gt;
&lt;p&gt;在重构的过程中偶然发现，在MacVim中，程序抛出任何异常，即便是有捕获逻辑，也会导致编辑器崩溃。在&lt;a href="http://stackoverflow.com/questions/5574702/how-to-print-to-stderr-in-python"&gt;这里&lt;/a&gt;简略地提到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the failure was actual a crash, through some strange combination of threading, matplotlib pyplot backend, and ssh X11 forwarding, sys.stderr had somehow been assigned to something which python complained wasn't a file-like object&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;于是将所有标准输出与标准错误输出语句换成另一种形式：&lt;/p&gt;
```python
# 原形式
sys.stdout.write('xxx')
sys.stderr.write('xxx')
# 新形式
print &gt;&gt; sys.stdout, 'xxx'
print &gt;&gt; sys.stderr, 'xxx'
```
&lt;p&gt;以上是新版主要变更的内容，此外，也顺便解决了开发过程中发现的个别Bug和做了其它一些改动：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change: The key "xmlrpc" of the settings list is dropped, a new one with the name "url" is added, you should set its value to the blog url.&lt;/li&gt;
&lt;li&gt;Change: Source code refactorings.&lt;/li&gt;
&lt;li&gt;Change: Solve the crash problem existing in MacVim only.&lt;/li&gt;
&lt;li&gt;Change: &lt;strong&gt;:UBConv&lt;/strong&gt; can be used in any buffer.&lt;/li&gt;
&lt;li&gt;Change: &lt;strong&gt;:UBThis&lt;/strong&gt; now has a third parameter, which enables convertions between syntaxes.&lt;/li&gt;
&lt;li&gt;Bugfix: The second parameter of &lt;strong&gt;:UBThis&lt;/strong&gt; cannot take effect.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这也是将源码从Google Code迁移到GitHub后发布的第一个新版本，更详细的信息请移步&lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;插件主页&lt;/a&gt;或GitHub上的&lt;a href="https://github.com/xbot/UltraBlog.vim"&gt;代码仓库&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>Double Commander: 免费、跨平台的Total Commander</title><link>http://0x3f.org/posts/double-commander/</link><pubDate>Wed, 31 Aug 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/double-commander/</guid><description>&lt;p&gt;由于Total Commander很贵，在Windows下又是必不可少的，我一直希望能找到一个TC的免费替代品。试用过很多免费的文件管理器，但都不理想。偶然看到&lt;a href="http://doublecmd.sourceforge.net/"&gt;Double Commander&lt;/a&gt;，才发现这几乎完全就是我想要的。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/ioR_w9MmX81q_5a8xjUPsA?feat=embedwebsite"&gt;&lt;img src="https://lh4.googleusercontent.com/-gkI4K4m5SSM/Tl31NceNNhI/AAAAAAAABzs/3AigwSN7whI/s640/doublecmd_screenshot.png" height="360" width="640" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;特性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;几乎完全模仿TC，甚至连插件的API都一致&lt;/li&gt;
&lt;li&gt;界面布局、样式高度可定制&lt;/li&gt;
&lt;li&gt;热键高度可定制&lt;/li&gt;
&lt;li&gt;开源、免费、跨平台&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;局限&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;功能相对TC少很多&lt;/li&gt;
&lt;li&gt;稳定性不是非常高&lt;/li&gt;
&lt;li&gt;运行速度稍嫌慢&lt;/li&gt;
&lt;li&gt;开发进度慢&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;小技巧&lt;/h2&gt;
&lt;h3&gt;热键设置&lt;/h3&gt;
&lt;p&gt;每个内置命令可以设置多个热键，每个热键可以指定参数，参数中可以使用环境变量，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/Z3jLMCGkoAbs1XC6yOhElg?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-lFMDaSny_gw/Tl31OKrfhMI/AAAAAAAABzs/2XX44Go-3zc/s640/doublecmd_hotkey.png" height="417" width="640" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;针对命令&lt;code&gt;cm_ChangeDir&lt;/code&gt;设置了两个热键，其中，给&lt;strong&gt;Ctrl+Home&lt;/strong&gt;指定的参数是&lt;strong&gt;$HOME&lt;/strong&gt;，给&lt;strong&gt;Ctrl+Shift+Home&lt;/strong&gt;指定的参数是&lt;strong&gt;$HOME/Desktop&lt;/strong&gt;，即分别切换到当前用户的主目录和桌面目录。&lt;/p&gt;
&lt;h3&gt;自定义文件类型命令&lt;/h3&gt;
&lt;p&gt;可以为每种文件类型定义多个命令，这些自定义命令将显示为上下文菜单的“动作”菜单的子菜单项。如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/m7mjk4g77XsMZw58ayJnEw?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-4Z6LcQg9YIc/Tl31OqcRqKI/AAAAAAAABzs/wJjK8noUWM8/s400/doublecmd_filetype_command_01.png" height="400" width="376" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;定义了名称为“Archive”的文件类型，关联了一系列的文件后缀名。然后添加了一个名为“解压缩到当前目录”的动作，并指定所执行的命令为&lt;code&gt;urxvt -e aunpack %f&lt;/code&gt;。其中，&lt;strong&gt;%f&lt;/strong&gt;是一个占位符，代表当前文件的全名。DC预置了几个占位符，可以点击命令输入框右侧图标是加号的按钮选择。&lt;/p&gt;
&lt;p&gt;最终的效果如下：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/mXYVL8uX1TNw0ENFur1PUQ?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-smFkdYyLMHE/Tl31QAWMNXI/AAAAAAAABzs/hIBW-yVpBuQ/s400/doublecmd_filetype_command_02.png" height="236" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;解决日期时间乱码的问题&lt;/h3&gt;
&lt;p&gt;截至版本0.5.0 beta，如果设置了使用日期时间字符串的格式为“yyyy-mm-dd hh:mm:ss”，在&lt;strong&gt;zh_CN.UTF-8&lt;/strong&gt;的区域设置下，字符串中将出现乱码：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/gMOlqF5DOQQ5otUEBon7lA?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-LfvO5yBH_F0/Tl3_d13FCNI/AAAAAAAAB0A/MHApuvTvkSg/s400/doublecmd_datetime_illegle_char.png" height="400" width="168" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;临时解决办法是以英文区域设置启动doublecmd：&lt;/p&gt;
```bash
#!/bin/bash
export LC_ALL=en_US.UTF-8
doublecmd &amp;
```
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Enable Code Snippet Highlighting For UltraBlog.vim Templates</title><link>http://0x3f.org/posts/enable-code-snippet-highlighting-for-ultrablog-vim-templates/</link><pubDate>Sat, 27 Aug 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/enable-code-snippet-highlighting-for-ultrablog-vim-templates/</guid><description>&lt;p&gt;Templates make it possible for users previewing posts in custom formats in &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;. However, there is more you can do with our highly customizable templates. This article discusses how to highlight code snippets in posts by the use of some third-party open-source tools.&lt;/p&gt;
&lt;p&gt;Before setting out to work, let me introduce the tools we are about to use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://softwaremaniacs.org/soft/highlight/en/"&gt;highlight.js&lt;/a&gt;: A javascript library which highlights code blocks in web pages automatically.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jquery.com/"&gt;jquery&lt;/a&gt;: The famous RIA development javascript library.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Download the upper two libraries and put them under any folder accessible to your webbrowser, in my case, it is &lt;strong&gt;/home/lenin/.vim/bundle/ultrablog/vendor/&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>Linux下双屏显示的设置</title><link>http://0x3f.org/posts/dualhead-display-on-linux/</link><pubDate>Thu, 04 Aug 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/dualhead-display-on-linux/</guid><description>&lt;p&gt;RandR是对X11的一个扩展协议，允许在不重启X的情况下修改输出的一些参数并使之生效，xrandr是该协议的命令行界面，它的功能之一就是用来设置双屏显示。&lt;/p&gt;
&lt;p&gt;缺省情况下，外接显示器后启用的是屏幕复制模式，即两个屏幕显示完全相同的内容。使用命令&lt;code&gt;xrandr -q&lt;/code&gt;查看当前的输出状态：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192
LVDS1 connected 1280x800+0+0 (normal left inverted right x axis y axis) 261mm x 163mm
1280x800 60.0&lt;em&gt;+ 60.0 50.0 &lt;br /&gt;
1024x768 75.1 70.1 60.0 &lt;br /&gt;
800x600 72.2 75.0 60.3 56.2 &lt;br /&gt;
768x576 75.0 72.0 60.0 &lt;br /&gt;
640x480 72.8 75.0 60.0 59.9 &lt;br /&gt;
VGA1 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 509mm x 286mm
1920x1080 60.0&lt;/em&gt;+
1680x1050 60.0 &lt;br /&gt;
1280x1024 75.0 60.0 &lt;br /&gt;
1440x900 59.9 &lt;br /&gt;
1280x960 60.0 &lt;br /&gt;
1024x768 75.1 70.1 60.0 &lt;br /&gt;
832x624 74.6 &lt;br /&gt;
800x600 72.2 75.0 60.3 56.2 &lt;br /&gt;
640x480 72.8 75.0 66.7 60.0 &lt;br /&gt;
720x400 70.1 &lt;br /&gt;
HDMI1 disconnected (normal left inverted right x axis y axis)
DP1 disconnected (normal left inverted right x axis y axis)
HDMI2 disconnected (normal left inverted right x axis y axis)
DP2 disconnected (normal left inverted right x axis y axis)
DP3 disconnected (normal left inverted right x axis y axis)&lt;/p&gt;</description></item><item><title>UltraBlog.vim v3.0释出：全文检索与事件驱动</title><link>http://0x3f.org/posts/ultrablog-v300-released/</link><pubDate>Mon, 25 Jul 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-v300-released/</guid><description>&lt;p&gt;用了一周的业余时间，昨天我释出了&lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;的3.0版。新版本主要加入了全文检索的功能，并引入事件驱动的模式。&lt;/p&gt;
&lt;p&gt;全文检索是我蓄谋已久的功能，一个不能搜索的博客客户端的管理功能是大打折扣的。得益于SQLite数据库和SQLAlchemy框架，全文检索的实现是很简单的，新增加的&lt;code&gt;:UBFind&lt;/code&gt;命令将在所有文章和页面的标题与内容中查询，并将搜索结果显示在一个可分页的列表中。这个命令支持任意多个关键词，各关键词之间遵循与的关系。此外，检索结果中，所有的关键词将被自动标记为高亮。&lt;/p&gt;
&lt;p&gt;事件驱动模式的引入是我悍然将版本号跳跃到3.x的主要原因。&lt;/p&gt;
&lt;p&gt;在前几个版本中，我实现了对多窗口的支持，它使得用户可以在新窗口中打开列表中的文章。但UltraBlog.vim最初开发的时候并没有考虑到多窗口的问题，所有命令都只针对当前窗口进行操作。这就有了缓冲区内容同步的问题，假如在一个新的缓冲区中打开了和另一个缓冲区相同的文章，则一个缓冲区内容的改变不会同步到另外一个中，这多少是有些隐患的。&lt;/p&gt;
&lt;p&gt;最直接的做法是在所有可能改变缓冲区内容的功能中加入对其它缓冲区的处理，但这样做有不少问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码耦合度太高，违反K.I.S.S原则，不利于今后的开发和维护&lt;/li&gt;
&lt;li&gt;函数体过长，我讨厌难看的代码&lt;/li&gt;
&lt;li&gt;代码冗余，重复劳动&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;事件驱动模式可以很好的解决以上问题，一个函数只干一件事，做完后一个事件抛出去，至于连带著要做什么，谁监听这个事件谁去处理，代码的耦合度很低，复用度很高，易于维护和阅读。&lt;/p&gt;
&lt;p&gt;UltraBlog.vim引入事件驱动模式处理缓冲区同步的问题。不同的操作抛出不同的事件，所有的事件继承自父类&lt;strong&gt;UBEvent&lt;/strong&gt;：&lt;/p&gt;
```python
class UBEvent:
def __init__(self, srcObj):
self.srcObj = srcObj
class UBDebugEvent(UBEvent): pass
class UBTmplDelEvent(UBEvent): pass
class UBTmplSaveEvent(UBEvent): pass
class UBLocalPostDelEvent(UBEvent): pass
class UBRemotePostDelEvent(UBEvent): pass
class UBPostSendEvent(UBEvent): pass
class UBPostSaveEvent(UBEvent): pass
```
&lt;p&gt;一个可能改变缓冲区内容的操作执行完后，创建一个特定的事件并将其加入到事件队列中。事件队列类中存放两个列表，一是事件队列，二是事件监听器列表；提供三个方法，分别用来注册事件监听器、对事件执行入队列操作和处理队列中所有事件：&lt;/p&gt;
```python
class UBEventQueue:
queue = []
listeners = []
@classmethod
def fireEvent(cls, evt):
cls.queue.append(evt)
@classmethod
def processEvents(cls):
for evt in cls.queue:
for listener in cls.listeners:
if listener.isTarget(evt):
cls.queue.remove(evt)
listener.processEvent(evt)
@classmethod
def registerListener(cls, lsnr):
cls.listeners.append(lsnr)
```
&lt;p&gt;事件队列对事件的处理是通过事件监听器进行的，每个事件监听器要实现两个功能：识别监听对象和处理监听对象。所有具体事件的监听类都是&lt;strong&gt;UBListener&lt;/strong&gt;的子类：&lt;/p&gt;</description></item><item><title>收入AOC E2343F</title><link>http://0x3f.org/posts/got-aoc-e2343f/</link><pubDate>Sun, 24 Jul 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/got-aoc-e2343f/</guid><description>&lt;p&gt;当初在深圳被公司的Dell Inspiron 1300吓怕了，所以不惜重金&lt;a href="http://0x3f.org/?p=819"&gt;收入&lt;/a&gt;了高配的Thinkpad X200 FN3。最近越来越觉得12寸的屏幕看代码实在是太局促了。&lt;/p&gt;
&lt;p&gt;今天中午收到AOC E2343F，979￥，23寸屏里算是价位很低的了，不算是很好的屏，不过看看代码、电影足够了。外接到X200上，人品不错，完美屏，没坏点，桌面环境下可以使用最大1920x1080x32分辨率，但是不知道为什么，&lt;code&gt;hwinfo --framebuffer&lt;/code&gt;列出的结果中没有这个最佳分辨率，&lt;a href="http://0x3f.org/?p=1377"&gt;KMS&lt;/a&gt;自动选用了1280x1024x32，可惜不能在&lt;a href="http://linuxtoy.org/archives/fbterm.html"&gt;fbterm&lt;/a&gt;下撒野了。&lt;/p&gt;
&lt;p&gt;下午复习了一下&lt;a href="http://zh.wikipedia.org/wiki/阿凡达"&gt;AVATAR&lt;/a&gt;，720P，有点儿冲动，&lt;a href="http://0x3f.org/?p=970"&gt;Intel GMA X4500&lt;/a&gt;还是很坚挺的。打开Vim，分割窗口，豁然开朗，对于这个根本目的，结果相当冲动。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/4HIWgaUq4G0PV4MnMapZ1Q?feat=embedwebsite"&gt;&lt;img src="https://lh4.googleusercontent.com/-jUv8m-8etm4/Tiqpqyp-LCI/AAAAAAAAByY/R8_PZiw3s_c/s400/C360_2011-07-23%25252018-38-10.jpg" height="300" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>使用PAC Manager管理SSH连接</title><link>http://0x3f.org/posts/manage-ssh-connections-using-pac-manager/</link><pubDate>Thu, 14 Jul 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/manage-ssh-connections-using-pac-manager/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文发表在今年一月份的『Linuxpilot』上，已经过了半年，可以放到博客上了。本文基于PAC 2.x版，最近PAC发布了3.0版，界面和功能都有一定的变化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://pacmanager.sourceforge.net"&gt;PAC Manager&lt;/a&gt;（以下简称PAC）是一个使用Perl编程语言和GTK图形界面开发套件实现的SSH/Telnet/Serial连接管理工具，是同类的PuTTY、SecureCRT、SSHMenu的一个开源、免费的替代品。&lt;/p&gt;
&lt;h2&gt;具备哪些特性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;可创建本地端口转发、远程端口转发和动态端口转发，并支持X图形界面转发&lt;/li&gt;
&lt;li&gt;对连接分组，方便管理较多连接&lt;/li&gt;
&lt;li&gt;将指定的、已打开的连接加入集群，同一集群的所有终端共享键盘输入&lt;/li&gt;
&lt;li&gt;虚拟终端窗口支持多标签&lt;/li&gt;
&lt;li&gt;虚拟终端窗口的样式可定制，支持半透明&lt;/li&gt;
&lt;li&gt;支持通过代理服务器建立连接&lt;/li&gt;
&lt;li&gt;支持通过Expect表达式进行自动交互&lt;/li&gt;
&lt;li&gt;支持使用本地和远程宏管理数量众多且复杂的常用指令&lt;/li&gt;
&lt;li&gt;支持定制连接前和断开后自动执行的指令&lt;/li&gt;
&lt;li&gt;为每个连接保存截图&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;针对重要特性的细解&lt;/h2&gt;
&lt;h3&gt;创建SSH隧道&lt;/h3&gt;
&lt;p&gt;假如当我们在进行诸如收发电邮、使用即时通讯工具聊天或者使用网络银行等网络通讯行为时，也许有些重要的数据我们不希望被明文传递；亦或某些资源受限于网络结构和防火墙等因素而不能被我们直接访问，这时我们往往就可以通过SSH的端口转发功能来实现。&lt;/p&gt;
&lt;p&gt;所谓端口转发，即是指将原本使用其它TCP端口访问的数据经由SSH连接占用的端口发送，加之这一过程也伴随有数据的加密和解密，因此也往往被称作“隧道”。根据连接方向的不同，SSH的隧道一般分为三种，即正向隧道、反向隧道和动态隧道；同时，根据端口转发方式的不同，这三种隧道又分别被称为本地端口转发、远程端口转发与动态端口转发。&lt;/p&gt;
&lt;p&gt;那么这三种端口转发方式彼此之间有什么异同，分别又都有什么用途呢？这里举个例子来说明一下。&lt;/p&gt;
&lt;p&gt;假设我的公司有一个较大的内部网络，而只有一台服务器作为网关对公网提供服务。如果我需要在家里的个人电脑上访问公司的办公系统，而这套系统又部署在内部网络中的一台服务器上、不能被公网访问，该怎么办呢？&lt;/p&gt;
&lt;p&gt;第一种情况，假设网关服务器对外提供了SSH服务，那么我就可以在家庭电脑上使用如下指令建立一个隧道：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ssh -L 9999:192.168.1.128:80 111.111.111.111&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这条指令中，192.168.1.128是公司办公系统服务器在内网中的IP地址，111.111.111.111是公司网关服务器的公网IP地址。整条指令的意思是：我在家庭电脑中访问本机的9999端口，就如同我在IP地址为111.111.111.111的公司网关服务器上访问IP地址为192.168.1.128的主机的80端口一样。因此，当这条指令执行成功后，我就可以在家庭电脑中通过访问9999端口来打开公司内部办公系统了。&lt;/p&gt;
&lt;p&gt;第二种情况，假设网关服务器不对外提供SSH服务但安装了SSH客户端，而我的家庭电脑却安装了SSH服务，那么我就可以在公司网关服务器上执行如下指令建立一个隧道：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ssh -R 9999:192.168.1.128:80 222.222.222.222&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这条指令中，222.222.222.222是家庭电脑的公网IP地址。整条指令的意思是：我在公网IP地址为222.222.222.222的电脑上访问9999端口，就如同在本机（公司网关服务器）上访问IP地址为192.168.1.128的主机的80端口一样。当我回到家中，就可以和前面一样通过访问9999端口来打开办公系统了。&lt;/p&gt;
&lt;p&gt;事实上，第一种情况是将本地端口映射为远程主机所能访问的资源，故称为本地端口转发；而第二种情况是将远程主机的端口映射为本机所能访问的资源，故称为远程端口转发。&lt;/p&gt;
&lt;p&gt;但无论是本地端口转发还是远程端口转发，都只能将一个资源转发到一个端口上，假若我要访问很多资源，岂非要建立很多SSH隧道，不但操作麻烦，而且浪费本机资源。这时，我们就可以使用第三种端口转发方式--动态端口转发：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ssh -D 9999 111.111.111.111&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这条指令的意思是：我在本机访问9999端口，就像在IP地址为111.111.111.111的主机上访问它所能访问的某些资源一样。这个所谓的“某些资源”，需要由我在发起访问请求时通过SSH隧道告诉远程主机，事实上，SSH的动态端口转发就是创建了一个SOCKS代理服务器。&lt;/p&gt;
&lt;p&gt;在PAC Manager中，我们可以在每个SSH连接的配置界面创建隧道。对于上面的例子，创建本地端口转发时，应点击“Local Port Forwarding”区域的“Add”按钮，并将本地端口、远程资源IP地址和端口分别填写到“Local Port”、“Remote Address”和“Remote Port”中：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/Gfzyo3h4hUrTUxA4YIlRuw?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/--l0NMNEs-Qs/Th70Q2lplvI/AAAAAAAABxo/EDBIPjRL0nY/s640/pac_manager_introduction-tunnel_01.png" height="166" width="640" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;截至当前最新的版本（2.4.1.3），PAC Manager尚未为远程端口转发提供像本地端口转发功能一样单独的配置界面，但可以使用高级选项功能实现。在“Advanced Options”输入框中填写如下内容：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/fru1uaGuVQ57mXRBiFRMeA?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-iFwTWK2ZL4M/Th70Q7NcE6I/AAAAAAAABxs/pTEh2LGkwV8/s640/pac_manager_introduction-tunnel_03.png" height="31" width="640" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如果需要建立多个远程端口转发，可以在“Advanced Options”中填写多个类似上面内容的选项，彼此之间使用空格分隔即可。&lt;/p&gt;
&lt;p&gt;创建动态端口转发时，应选中“Dynamic Port Forwarding”区域前面的复选框，然后填写“Forwarded SOCKS Port”即可：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/hnRb67QlipzpHb_IaeyYiw?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/-JHN7-EI7pjc/Th70QhAOCUI/AAAAAAAABxk/4D2e1SpcS-U/s640/pac_manager_introduction-tunnel_02.png" height="55" width="640" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;连接前及断开后的自动指令&lt;/h3&gt;
&lt;p&gt;通过在PAC Manager中定义连接前和断开后的自动指令，我们可以指定一些在相应的SSH连接建立之前及断开之后通常要在本机执行的指令。&lt;/p&gt;
&lt;p&gt;例如假设我使用的是计时收费的网络服务，为了节省资费，我希望只在每次建立SSH连接时才激活网络服务，并且在完成工作后断开SSH连接时自动断开网络服务。那么就可以在“Pre Exec”中定义激活网络服务的指令，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/_P1JaaI5sF8gDTMulaljVA?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-nPz5VHhK0vk/Th70MQLOVOI/AAAAAAAABxM/Q-mwNmyxzOo/s640/pac_manager_introduction-exec_01.png" height="136" width="640" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>APC、文件和Memcached效率对比</title><link>http://0x3f.org/posts/comparison-of-efficiency-for-apc-file-memcached/</link><pubDate>Wed, 13 Jul 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/comparison-of-efficiency-for-apc-file-memcached/</guid><description>&lt;p&gt;对一个保存了100个对象实例的数组进行300次读写，该数组序列化后大小为232KB。&lt;/p&gt;
&lt;h2&gt;测试环境&lt;/h2&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;网络服务器&lt;/th&gt;
&lt;th&gt;PHP版本&lt;/th&gt;
&lt;th&gt;操作系统&lt;/th&gt;
&lt;th&gt;硬件配置&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NGINX v1.0.4&lt;/td&gt;
&lt;td&gt;PHP-FPM v5.3.6&lt;br&gt;APC启用&lt;/td&gt;
&lt;td&gt;Archlinux 32bit&lt;/td&gt;
&lt;td&gt;Intel(R) Core(TM)2 Duo CPU T9400 @ 2.53GHz&lt;br&gt;Mem: 3G DDR3&lt;br&gt;Disk: 5400r/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2&gt;测试脚本&lt;/h2&gt;
&lt;p&gt;测试数据：&lt;/p&gt;
```php
&lt;?php
/*
* @file data.php
*/
class XTest
{
var $x0;
var $x1;
var $x2;
var $x3;
var $x4;
var $x5;
var $x6;
var $x7;
var $x8;
var $x9;
var $x10;
var $x11;
var $x12;
var $x13;
var $x14;
var $x15;
var $x16;
var $x17;
var $x18;
var $x19;
var $x20;
var $x21;
var $x22;
var $x23;
var $x24;
var $x25;
var $x26;
var $x27;
var $x28;
var $x29;
var $x30;
var $x31;
var $x32;
var $x33;
var $x34;
var $x35;
var $x36;
var $x37;
var $x38;
var $x39;
var $x40;
var $x41;
var $x42;
var $x43;
var $x44;
var $x45;
var $x46;
var $x47;
var $x48;
var $x49;
var $x50;
var $x51;
var $x52;
var $x53;
var $x54;
var $x55;
var $x56;
var $x57;
var $x58;
var $x59;
var $x60;
var $x61;
var $x62;
var $x63;
var $x64;
var $x65;
var $x66;
var $x67;
var $x68;
var $x69;
var $x70;
var $x71;
var $x72;
var $x73;
var $x74;
var $x75;
var $x76;
var $x77;
var $x78;
var $x79;
var $x80;
var $x81;
var $x82;
var $x83;
var $x84;
var $x85;
var $x86;
var $x87;
var $x88;
var $x89;
var $x90;
var $x91;
var $x92;
var $x93;
var $x94;
var $x95;
var $x96;
var $x97;
var $x98;
var $x99;
function __construct()
{
$this-&gt;x0 = 1234567890;
$this-&gt;x1 = 1234567890;
$this-&gt;x2 = 1234567890;
$this-&gt;x3 = 1234567890;
$this-&gt;x4 = 1234567890;
$this-&gt;x5 = 1234567890;
$this-&gt;x6 = 1234567890;
$this-&gt;x7 = 1234567890;
$this-&gt;x8 = 1234567890;
$this-&gt;x9 = 1234567890;
$this-&gt;x10 = 1234567890;
$this-&gt;x11 = 1234567890;
$this-&gt;x12 = 1234567890;
$this-&gt;x13 = 1234567890;
$this-&gt;x14 = 1234567890;
$this-&gt;x15 = 1234567890;
$this-&gt;x16 = 1234567890;
$this-&gt;x17 = 1234567890;
$this-&gt;x18 = 1234567890;
$this-&gt;x19 = 1234567890;
$this-&gt;x20 = 1234567890;
$this-&gt;x21 = 1234567890;
$this-&gt;x22 = 1234567890;
$this-&gt;x23 = 1234567890;
$this-&gt;x24 = 1234567890;
$this-&gt;x25 = 1234567890;
$this-&gt;x26 = 1234567890;
$this-&gt;x27 = 1234567890;
$this-&gt;x28 = 1234567890;
$this-&gt;x29 = 1234567890;
$this-&gt;x30 = 1234567890;
$this-&gt;x31 = 1234567890;
$this-&gt;x32 = 1234567890;
$this-&gt;x33 = 1234567890;
$this-&gt;x34 = 1234567890;
$this-&gt;x35 = 1234567890;
$this-&gt;x36 = 1234567890;
$this-&gt;x37 = 1234567890;
$this-&gt;x38 = 1234567890;
$this-&gt;x39 = 1234567890;
$this-&gt;x40 = 1234567890;
$this-&gt;x41 = 1234567890;
$this-&gt;x42 = 1234567890;
$this-&gt;x43 = 1234567890;
$this-&gt;x44 = 1234567890;
$this-&gt;x45 = 1234567890;
$this-&gt;x46 = 1234567890;
$this-&gt;x47 = 1234567890;
$this-&gt;x48 = 1234567890;
$this-&gt;x49 = 1234567890;
$this-&gt;x50 = 1234567890;
$this-&gt;x51 = 1234567890;
$this-&gt;x52 = 1234567890;
$this-&gt;x53 = 1234567890;
$this-&gt;x54 = 1234567890;
$this-&gt;x55 = 1234567890;
$this-&gt;x56 = 1234567890;
$this-&gt;x57 = 1234567890;
$this-&gt;x58 = 1234567890;
$this-&gt;x59 = 1234567890;
$this-&gt;x60 = 1234567890;
$this-&gt;x61 = 1234567890;
$this-&gt;x62 = 1234567890;
$this-&gt;x63 = 1234567890;
$this-&gt;x64 = 1234567890;
$this-&gt;x65 = 1234567890;
$this-&gt;x66 = 1234567890;
$this-&gt;x67 = 1234567890;
$this-&gt;x68 = 1234567890;
$this-&gt;x69 = 1234567890;
$this-&gt;x70 = 1234567890;
$this-&gt;x71 = 1234567890;
$this-&gt;x72 = 1234567890;
$this-&gt;x73 = 1234567890;
$this-&gt;x74 = 1234567890;
$this-&gt;x75 = 1234567890;
$this-&gt;x76 = 1234567890;
$this-&gt;x77 = 1234567890;
$this-&gt;x78 = 1234567890;
$this-&gt;x79 = 1234567890;
$this-&gt;x80 = 1234567890;
$this-&gt;x81 = 1234567890;
$this-&gt;x82 = 1234567890;
$this-&gt;x83 = 1234567890;
$this-&gt;x84 = 1234567890;
$this-&gt;x85 = 1234567890;
$this-&gt;x86 = 1234567890;
$this-&gt;x87 = 1234567890;
$this-&gt;x88 = 1234567890;
$this-&gt;x89 = 1234567890;
$this-&gt;x90 = 1234567890;
$this-&gt;x91 = 1234567890;
$this-&gt;x92 = 1234567890;
$this-&gt;x93 = 1234567890;
$this-&gt;x94 = 1234567890;
$this-&gt;x95 = 1234567890;
$this-&gt;x96 = 1234567890;
$this-&gt;x97 = 1234567890;
$this-&gt;x98 = 1234567890;
$this-&gt;x99 = 1234567890;
}
}
$repeat = 300;
$arr = array();
for ($i = 0; $i &lt; 100; $i++) {
$arr[] = new XTest;
}
?&gt;
```
&lt;p&gt;APC:&lt;/p&gt;</description></item><item><title>隐藏InstallShield对话框控件的方法</title><link>http://0x3f.org/posts/how-to-hide-dialog-in-installshield/</link><pubDate>Wed, 22 Jun 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-hide-dialog-in-installshield/</guid><description>&lt;p&gt;SQLServerSelectLogin对话框中如果选择Windows身份验证，在附加数据库时会因权限不够而失败，所以应该隐藏这个选项，从而要求用户只执行SQL身份验证。&lt;/p&gt;
&lt;p&gt;但是如果在定制对话框布局时直接删除两个单选框，会导致用户输入的用户名和密码不能被安装程序获取，并且InstallShield也没有提供隐藏这些控件的属性。解决方法是修改控件的定位属性，将其定位到对话框的大小范围之外：&lt;/p&gt;
&lt;p&gt;要达到的目标：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/pDxRP_-E5wL7hAoCGYhHXQ?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-069F7ZsOWOo/TgHdXDlb7iI/AAAAAAAABv0/zd6y0KAlYWM/s400/SQLServerSelectLogin_Customization_01.png" height="299" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;修改Top属性，将指定的控件定位在对话框之外：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/5NUaJ2Re61aWiUcJwDOHZg?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-9xthNFn9b2U/TgHdXnU-TmI/AAAAAAAABv4/-pQdJWF3nM8/s400/SQLServerSelectLogin_Customization_02.png" height="302" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最终效果：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/PImOz5YLlQKHAS2KUfggyw?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-o2S0V7IzHKg/TgHdWxwEWMI/AAAAAAAABvw/2q4M26A_O2s/s400/SQLServerSelectLogin_Customization_03.png" height="299" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>读完『Ext JS IN Action』</title><link>http://0x3f.org/posts/after-reading-extjs-in-action/</link><pubDate>Tue, 21 Jun 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-extjs-in-action/</guid><description>&lt;p&gt;这是本需要仔细读的书，对ExtJS的主要控件有比较详细的解说，有一定的原理性解释，并且对扩展ExtJS和ExtJS项目开发的模式有一些介绍。但不涉及底层特性，例如DOM、AJAX等。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/-SKr3JvnYwcLN0fb6sxCpw?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-buAuqjZT0o4/Tf9kmGOt4vI/AAAAAAAABvQ/LezmUW7CJ74/s400/ExtJS_In_Action.jpg" height="400" width="319" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>UltraBlog.vim v2.3.0 Released With Templates</title><link>http://0x3f.org/posts/ultrablog-v230-released/</link><pubDate>Mon, 13 Jun 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-v230-released/</guid><description>&lt;p&gt;I released the new version 2.3.0 of &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt; last week. The main improvement in this version is that templates are introduced in.&lt;/p&gt;
&lt;p&gt;Templates are simply HTML strings, they are used to preview posts/pages in the browser locally. This feature is a reparation for the remote previewing, due to the limit of the API, users cannot send a post to Wordpress as draft and preview it without affecting the post status if the post has been published. With templates, they do not have to send drafts to blogs to preview the final effect, but preview drafts directly in the browser in a pre-defined style. Templates can be created as many as users like and their looks can be customized with CSS, HTML and Javascript.&lt;/p&gt;</description></item><item><title>Vim自定义命令的参数自动补全</title><link>http://0x3f.org/posts/how-to-define-auto-completion-for-vim-commands/</link><pubDate>Sat, 11 Jun 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/how-to-define-auto-completion-for-vim-commands/</guid><description>&lt;p&gt;&lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;起初的几个版本采用增加命令个数的方式减少每个命令的参数个数，目的是降低命令格式记忆的难度。从2.3.0版本起，开始采用Vim自定义命令的一些高级特性，精简命令个数，虽然参数个数增加了，但由于实现了参数补全，反而更加直观。&lt;/p&gt;
&lt;p&gt;Vim对自定义命令提供了多种补全参数的方式，详见&lt;code&gt;:h command-complete&lt;/code&gt;。其中，最常用的当属&lt;strong&gt;custom&lt;/strong&gt;：&lt;/p&gt;
```vim
command! -nargs=? -complete=custom,StatusCmpl UBSend exec('py ub_send_item(&lt;f-args&gt;)')
```
&lt;p&gt;以上代码定义了一个自定义命令&lt;strong&gt;UBSend&lt;/strong&gt;，它可以获得一个或零个参数（&lt;em&gt;-nargs=?&lt;/em&gt;），如果指定参数，则补全方式采用&lt;strong&gt;custom&lt;/strong&gt;，该方式调用一个名为&lt;strong&gt;StatusCmpl&lt;/strong&gt;的函数并以其返回值作为补全的值域：&lt;/p&gt;
```vim
function! StatusCmpl(ArgLead, CmdLine, CursorPos)
return "draft\npublish\nprivate\npending\n"
endfunction
```
&lt;p&gt;从以上代码可以看出，该函数需要接受三个参数，返回值应该是一个用换行符“\n”分割的字符串，在执行补全时，Vim自动使用正则表达式匹配备选项。对于只有一个参数的情况，这种实现方式简单高效。&lt;/p&gt;
&lt;p&gt;对于参数较多的情况，&lt;strong&gt;customlist&lt;/strong&gt;补全方式最为适用：&lt;/p&gt;
```vim
command! -nargs=* -complete=customlist,UBNewCmpl UBNew exec('py ub_new_item(&lt;f-args&gt;)')
```
&lt;p&gt;以上代码定义了命令&lt;strong&gt;UBNew&lt;/strong&gt;，&lt;strong&gt;customlist&lt;/strong&gt;补全方式调用函数&lt;strong&gt;UBNewCmpl&lt;/strong&gt;获取补全的值域：&lt;/p&gt;
```vim
function! UBNewCmpl(ArgLead, CmdLine, CursorPos)
let lst = split(a:CmdLine)
if len(a:ArgLead)&gt;0
let lst = lst[0:-2]
endif
let results = []
" For the first argument, complete the object type
if len(lst)==1
let objects = ['post','page','tmpl']
for obj in objects
if stridx(obj,a:ArgLead)==0
call add(results,obj)
endif
endfor
" For the second argument, complete the syntax for :UBNew post or :UBNew
" page
elseif len(lst)==2 &amp;&amp; count(['post', 'page'], lst[1])==1
let syntaxes = ['markdown','html','rst','textile','latex']
for synx in syntaxes
if stridx(synx,a:ArgLead)==0
call add(results,synx)
endif
endfor
endif
return results
endfunction
```
&lt;p&gt;这时侯，前面提到的三个参数就派上用场了。&lt;strong&gt;ArgLead&lt;/strong&gt;是进行补全时，已输入的参数部分，例如输入&lt;code&gt;:UBNew p&lt;/code&gt;，然后按Tab键，则ArgLead的值就是“p”；&lt;strong&gt;CmdLine&lt;/strong&gt;是已经输入的命令的全部，按上例，这个参数的值就是“UBNew p”；&lt;strong&gt;CursorPost&lt;/strong&gt;是当前光标距离命令行开头的字符数。利用这三个参数，就可以判断正在补全命令的第几个参数，进而利用ArgLead筛选该参数的值域。&lt;/p&gt;</description></item><item><title>聚合个人资讯</title><link>http://0x3f.org/posts/burn-personal-info-into-one-feed-using-yahoo-pipes/</link><pubDate>Wed, 08 Jun 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/burn-personal-info-into-one-feed-using-yahoo-pipes/</guid><description>&lt;p&gt;前段时间我把Twitter整合进博客之后，忽然觉得，既然微博已经很重要了，就应该加强它的地位，使其与博客分庭抗礼。于是开始用&lt;a href="http://www.blueprintcss.org/"&gt;blueprint&lt;/a&gt;做CSS框架，对两三年没变过的&lt;a href="http://0x3f.org/?p=198"&gt;iterse&lt;/a&gt;做一些调整。&lt;/p&gt;
&lt;p&gt;我对前端不太熟悉，这时候CSS框架的优越性就充分体现出来了，它让页面的布局变得相当容易，尤其是对前端设计最烦人的对多浏览器的兼容问题。现在的主题采用流行的950px宽度，比以前800px要宽裕了不少。其中，三分之一的宽度分给侧边栏，剩余部分留给博客文章列表，仍然采用两栏结构。&lt;/p&gt;
&lt;p&gt;我在页面顶部加了顶栏，将原来侧边栏中的分类、归档、页面、搜索框、RSS订阅全部扔到里面。同时提升Twitter和最新评论列表的位置，增加它们显示条目的数量，以加强这两个时效性和互动性比较强的栏目。&lt;/p&gt;
&lt;p&gt;然后我觉得资讯订阅中的内容也不应该再仅仅局限于博客文章了，应该把我在用的Twitter、豆瓣、Google Reader分享、PicasaWeb等服务中我的资讯也聚合进来。&lt;del&gt;开始的时候打算用&lt;a href="http://pipes.yahoo.com/"&gt;Yahoo! Pipes&lt;/a&gt;，后来突然发现&lt;a href="http://friendfeed.com"&gt;FriendFeed&lt;/a&gt;就可以做这个事，而且更好用，于是将原来烧录的&lt;a href="http://feeds.feedburner.com/leninlee"&gt;http://feeds.feedburner.com/leninlee&lt;/a&gt;指向FriendFeed。&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;所以对于订阅原来的FeedBurner烧录的feed的读者，如果希望仍然只订阅博客文章，可以订阅&lt;a href="http://feeds.feedburner.com/sinolog"&gt;http://feeds.feedburner.com/sinolog&lt;/a&gt;。这两个feed都放到了顶栏中，请以各种姿态翻墙订阅。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2011-06-08 更新&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;时隔一天，我认识到一个错误，FriendFeed毕竟还是一个微博，用它聚合个人资讯是不合适的，比如不能全文输出博客文章。最终还是使用Yahoo! Pipes，这货很强大、很好用。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/A47YaQXgVCk4TjIny4MSZQ?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-XeC4asNS_rU/Te-jeQU1jbI/AAAAAAAABs4/qMPXWNyciuA/s400/2011-06-09.00%25253A33%25253A19.%2525E6%252593%2525B7%2525E5%25258F%252596%2525E9%252581%2525B8%2525E5%25258F%252596%2525E5%25258D%252580%2525E5%25259F%25259F.01.png" height="239" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;另外，&lt;a href="http://twitter2rss.com/"&gt;twitter2rss&lt;/a&gt;是支持OAuth的Twitter烧录服务，非常好用。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>人性化Vim的预览窗口</title><link>http://0x3f.org/posts/humanize-preview-window-in-vim/</link><pubDate>Sun, 29 May 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/humanize-preview-window-in-vim/</guid><description>&lt;p&gt;Vim的预览窗口由 &lt;code&gt;:ptag&lt;/code&gt; 等命令触发，可用于预览函数定义。但在缺省情况下，预览窗口的高度是固定的，对于注释信息较多的函数，往往不能完全显示注释，而对于注释较少的函数，又会有多余的行浪费屏幕空间。&lt;/p&gt;
&lt;p&gt;下面的函数用于解决这个问题：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; 调用:ptag命令预览光标所在&amp;lt;word&amp;gt;的定义&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; 对类C语言风格的函数/方法定义和注释有效，对其余情况仍沿用:ptag的原有效果&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;PTagIt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ptag &amp;#34;&lt;/span&gt;.&lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;cword&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cwin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;winnr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;wincmd&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lnr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;lnr&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;foldlevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;normal&lt;/span&gt; &lt;span class="nx"&gt;zo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;chead&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linestr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lnr&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;linestr&lt;/span&gt; &lt;span class="p"&gt;=~&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;^\s*\*/&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ptr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lnr&lt;/span&gt;&lt;span class="m"&gt;-2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;while&lt;/span&gt; &lt;span class="nx"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linestr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;linestr&lt;/span&gt; &lt;span class="p"&gt;=~&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;^\s*/\*&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;chead&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ptr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ptr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ptr&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;endwhile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;chead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;resize &amp;#39;&lt;/span&gt;.&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lnr&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;chead&lt;/span&gt;&lt;span class="p"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;normal &amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;chead&lt;/span&gt;.&lt;span class="s2"&gt;&amp;#34;z\&amp;lt;CR&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;normal &amp;#39;&lt;/span&gt;.&lt;span class="nx"&gt;lnr&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;G&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="nx"&gt;cwin&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;wincmd w&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;pp&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;PTagIt&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt; :&lt;span class="nx"&gt;pclose&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;例如对于如下的函数定义：&lt;/p&gt;</description></item><item><title>ack: grep的同类替代品</title><link>http://0x3f.org/posts/use-ack-as-an-alternative-to-grep/</link><pubDate>Mon, 09 May 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/use-ack-as-an-alternative-to-grep/</guid><description>&lt;p&gt;&lt;a href="http://betterthangrep.com"&gt;ack&lt;/a&gt;是一个perl脚本，是grep的一个可选替换。&lt;/p&gt;
&lt;p&gt;有以下优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为程序员设计，使用方便，输入较少
&lt;ul&gt;
&lt;li&gt;默认递归搜索&lt;/li&gt;
&lt;li&gt;缺省提供多种文件类型供选，文件类型对应的后缀名可修改&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;使用perl的正则表达式，而grep只支持其一个子集&lt;/li&gt;
&lt;li&gt;搜索结果高亮输出&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;很多人以讹传讹，使人容易对ack的搜索速度产生误解。ack的官方宣传中说比grep快，其前提是ack可方便地针对部分后缀的文件进行搜索，而grep默认对所有文件搜索。ack的官方文档中明确指出，在对大量文件进行搜索时，grep的速度还是最快的。&lt;/p&gt;
&lt;h2&gt;~/.ackrc&lt;/h2&gt;
&lt;p&gt;使用此配置文件存储ack的常用选项。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;-i
--type-add
php=.lib&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如上所示，该文件中每一行应该是ack命令行参数中用空格分隔的一个部分。&lt;/p&gt;
&lt;h2&gt;例子&lt;/h2&gt;
&lt;p&gt;如果搜索的关键词是正则表达式，在Linux下必须将其用双引号包围起来。&lt;/p&gt;
&lt;p&gt;如：&lt;/p&gt;
```bash
ack "gbldb\s*="
```
&lt;h2&gt;Windows下的安装&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;安装&lt;a href="http://strawberryperl.com"&gt;strawberryperl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;保存&lt;a href="http://betterthangrep.com/ack-standalone"&gt;ack.pl&lt;/a&gt;到&lt;em&gt;C:\bin&lt;/em&gt;&lt;/li&gt;
```dos
@echo off
perl.exe c:/bin/ack.pl %*
```
&lt;li&gt;将&lt;em&gt;C:\bin&lt;/em&gt;加入环境变量&lt;strong&gt;%PATH%&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;资源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.vim.org/scripts/script.php?script_id=2572"&gt;ack.vim&lt;/a&gt;: Vim使用ack的辅助扩展&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>读完《Nginx HTTP Server》</title><link>http://0x3f.org/posts/after-reading-nginx-http-server/</link><pubDate>Fri, 29 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-nginx-http-server/</guid><description>&lt;p&gt;昨天晚上在杭州飞北京的飞机上读完了这本书，用Kindle DXG。&lt;/p&gt;
&lt;p&gt;作者是江苏科技大学的一位外籍老师，所以这本书也很有教科书的风格，先用一章的篇幅介绍Linux的相关概念和日常操作，而后通过和Apache的对比讲述了Nginx的主要特性，并使用Wordpress、MediaWiki等作了实例讲解。面面俱到，简单易懂，但并不深入。&lt;/p&gt;
&lt;p&gt;目前介绍Nginx的书还不多，这本算得上是其中很好的一本。但是前六十页都是介绍Linux的基本概念，和后面的内容关系不大，显得很突兀，且很不KISS，对于一本只有三百多页的小书来说，这个篇幅很令人遐想。抛开这一点，这本书当属眼下入门Nginx的优秀指南。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/1wfTXx_Zpcr1BVlrh5KD_A?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/_ceUJ_lBTHzc/TbrPHzzLMJI/AAAAAAAABqY/2cOJEsushfU/s400/1.png" height="400" width="309" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>PHP序列化方案效率比较</title><link>http://0x3f.org/posts/comparison-of-serialization-methods-of-php/</link><pubDate>Sun, 17 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/comparison-of-serialization-methods-of-php/</guid><description>&lt;p&gt;同时对以下几种PHP的序列化方案进行了测试：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;serialize() and unserialize()&lt;/li&gt;
&lt;li&gt;json_encode() and json_decode()&lt;/li&gt;
&lt;li&gt;msgpack_serialize() and msgpack_unserialize()&lt;/li&gt;
&lt;li&gt;igbinary_serialize() and igbinary_unserialize()&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;测试环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OS: Archlinux 32-bit&lt;/li&gt;
&lt;li&gt;CPU: CORE 2 DUO T9400, 2.53GHz&lt;/li&gt;
&lt;li&gt;Mem: DDR3, 3G&lt;/li&gt;
&lt;li&gt;Server: nginx v1.0.0&lt;/li&gt;
&lt;li&gt;PHP: php v5.3.6 + php-fpm&lt;/li&gt;
&lt;li&gt;Profiler: xhprof v0.9.2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;测试代码块：&lt;/p&gt;
```php
&lt;?php
class Test{
function __construct(){
$this-&gt;value = str_repeat('a', 1000);
}
}
function produce($num)
{
$arr = array();
for ($i = 0; $i &lt; $num; $i++) {
$arr[] = new Test();
}
$data = serialize($arr);
$arr = unserialize($data);
$data = json_encode($arr);
$arr = json_decode($data);
$data = msgpack_serialize($arr);
$arr = msgpack_unserialize($data);
$data = igbinary_serialize($arr);
$arr = igbinary_unserialize($data);
}
produce(10000);
?&gt;
```
&lt;p&gt;测试结果：&lt;/p&gt;</description></item><item><title>UltraBlog.vim开发手记</title><link>http://0x3f.org/posts/ultrablog-development-note/</link><pubDate>Mon, 11 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-development-note/</guid><description>&lt;p&gt;对于&lt;a href="http://blog.sina.com.cn/s/blog_694377f90100rmko.html"&gt;博客已死&lt;/a&gt;的说法，我一点都不感到奇怪。早在几年前博客还比较火的时候我就表达过对博客泡沫的&lt;a href="http://0x3f.org/?p=209"&gt;看法&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;经历了短暂的&lt;a href="http://0x3f.org/?p=354"&gt;tumblog&lt;/a&gt;的风头，微博成为现在最火的媒介。说博客已死，无非就是说微博将成为个人信息传播的主流。好吧，现在我知道那时候我所说的不懂什么是博客的人都去干什么了。&lt;/p&gt;
&lt;p&gt;但是博客还是会继续发展，微博的兴起只会减少滥竽充数。因为微博突出的是时效性，最缺乏的是系统性和可重复更新的能力。微博的短处，正是博客的长处。这让我对博客有了一个新的、迟到了很久的认识──一个好的博客，它的文章不应该是写掉就忘的，而应该是不断地更新著的。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;就是出于这个需要而写的。&lt;/p&gt;
&lt;p&gt;我对博客客户端的使用大概可以追溯到四五年前，那时候博客正火，在比较了几个&lt;a href="http://en.wikipedia.org/wiki/Blog_service_provider"&gt;BSP&lt;/a&gt;后选择了&lt;a href="http://www.blogcn.com/"&gt;中国博客网&lt;/a&gt;，就是因为他们提供桌面客户端。后来独博之后也试用过几个通用的客户端，但都没坚持多久，最根本的原因是它们几乎无一例外地都是&lt;a href="http://zh.wikipedia.org/wiki/%E6%89%80%E8%A6%8B%E5%8D%B3%E6%89%80%E5%BE%97"&gt;WYSIWYG&lt;/a&gt;。而WYSIWYG的编辑器生成的HTML源码几乎都使用inline的样式，这就导致文章的排版布局很难控制，我对WYSIWYG其实是很抵触的，至今都不怎么用Office这类东西。&lt;/p&gt;
&lt;p&gt;后来我意识到，我所需要的是样式与内容分离，于是准备自己写一个&lt;a href="http://0x3f.org/?p=331"&gt;客户端&lt;/a&gt;，后来由于工作的原因不了了之。与此同时，我自定义了一套文章格式并用Java写了一个转换文章到HTML的&lt;a href="http://0x3f.org/?p=342"&gt;工具&lt;/a&gt;，直到后来发现&lt;a href="http://0x3f.org/?p=383"&gt;Markdown&lt;/a&gt;，我才知道我其实是需要一个轻量标记语言。&lt;/p&gt;
&lt;p&gt;使用Markdown之后，写博客开始变得轻松愉快。我一度用过一段时间&lt;a href="http://www.scintilla.org/SciTE.html"&gt;SciTE&lt;/a&gt;，还用&lt;a href="http://zh.wikipedia.org/wiki/Lua"&gt;Lua&lt;/a&gt;写了个&lt;a href="http://0x3f.org/?p=499"&gt;辅助脚本&lt;/a&gt;。但是我需要一个完整的客户端来管理文章，而这是一个编辑器所不能胜任的，所以就著手实现一个支持Markdown的&lt;a href="http://0x3f.org/?p=812"&gt;客户端&lt;/a&gt;。这一次走得比较远，&lt;a href="http://0x3f.org/?p=812"&gt;ForeverFantasy&lt;/a&gt;最终达到了可用的程度，我一度用它写过一段时间的博客。但是作为一个Vim重症患者，wxPython的编辑器部件是远远达不到我需要的水平的。虽然后来还&lt;a href="http://0x3f.org/?p=1409"&gt;实现&lt;/a&gt;了调用外部程序处理文章内容（&lt;em&gt;当然也可以调用Vim&lt;/em&gt;），但总归觉得不舒服，至今已经一年没更新了。&lt;/p&gt;
&lt;p&gt;直到前段时间试用了一下&lt;a href="http://0x3f.org/?p=1861"&gt;VimRepress&lt;/a&gt;，在修改这个插件的时候突然受到启发，我这几年的需求原来是可以这么简单地解决的。&lt;/p&gt;
&lt;p&gt;其实在几年前&lt;a href="http://www.vim.org/scripts/script.php?script_id=1953"&gt;vimpress&lt;/a&gt;刚刚发布的时候我就了解过这个东西，包括此后接连发布的几个Vim写博客的插件，它们和我原来写的SciTE的那个辅助脚本没有本质的区别，都是博客编辑器。与完整的客户端相比，编辑器缺少对本地文章源码的管理，而且它们不记录文章源码和发布的文章的关联关系，简单地说是无状态的。这不符合博客文章持续更新的观点。&lt;/p&gt;
&lt;p&gt;UltraBlog.vim使用&lt;a href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt;做数据库抽象层，将所有文章的源码及其状态保存在本地的一个SQLite数据库中，并且以此为基础，通过&lt;a href="http://en.wikipedia.org/wiki/XML-RPC"&gt;XMLRPC&lt;/a&gt;接口实现对博客文章、页面的&lt;a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete"&gt;CRUD&lt;/a&gt;操作。同时利用Vim分模式的特点实现了可分页的文章列表和文章编辑视图。&lt;/p&gt;
&lt;p&gt;UltraBlog.vim目前支持Markdown和HTML两种格式的文章，它最大的特点是在Markdown格式的源码和发布到博客中的文章之间建立联系，你可以随时修改本地数据库中的Markdown源码并更新博客中对应的文章。&lt;/p&gt;
&lt;p&gt;新的功能还会不断地加入。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>GNOME 3 Launch Party</title><link>http://0x3f.org/posts/gnome3-launch-party/</link><pubDate>Sat, 09 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/gnome3-launch-party/</guid><description>&lt;p&gt;在保福寺桥南下了车我就迷失了，作为一个G7er，问路太跌份，于是自信满满地祭出G7，结果Google导航很淡定地告诉我──您所在的区域不支持导航！有木有搞错，有木有，有木有，有木有啊！最后在3G、GPS、电子指南针全开的情况下，跟著Google地图上的小箭头在中关村南街、中关村三街流窜了半个小时，后来我才知道，我规则地绕中科院研究生院做了一次顺时针圆周运动。&lt;/p&gt;
&lt;p&gt;好吧，我最后还是人肉到目的地的，感谢给我指路的朋友，他让我终于找到了那条隐藏地很深的小路，你敢隐藏得再深一点吗？！&lt;/p&gt;
&lt;p&gt;有时侯这个世界真的很给力，当我比原定时间晚半个多钟头到达会场的时候，他们居然还没有开始！&lt;/p&gt;
&lt;p&gt;爱美丽宣布开会：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/MBRi_eVDmFJ4jzfOMIq-YQ?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/_ceUJ_lBTHzc/TaBbMJwy5MI/AAAAAAAABoo/lIaHTDG2iVA/s400/C360_2011-04-09%2014-24-03.jpg" height="300" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;程大龙介绍GNOME 3：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/Hh7BSY-1iIYZoP-PyK_SbA?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/_ceUJ_lBTHzc/TaBbNKxxCrI/AAAAAAAABoc/-gYdCmNOF8k/s400/C360_2011-04-09%2014-59-44.jpg" height="300" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这小哥儿原来是北航的，后生可畏啊，当初我开始玩儿Linux的时候他刚脱离李雷和韩梅梅吧。&lt;/p&gt;
&lt;p&gt;来一张火爆的：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/8_v2QCOBajRfOlxI92AL3Q?feat=embedwebsite"&gt;&lt;img src="https://lh4.googleusercontent.com/_ceUJ_lBTHzc/TaBbO4X4PcI/AAAAAAAABok/9mgCyktfICk/s400/C360_2011-04-09%2016-29-59.jpg" height="300" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今天最意外的亮点就是这个什么××××协会的西班牙舞了，开始、中间和结束的时候各来了一段，俺们红小兵也看不懂，就是感觉很劲爆，反正只要是不规则的事物我都喜欢。&lt;/p&gt;
&lt;p&gt;其它的，两岸三地的视频会议很失败，搞个高速VPN不行吗？瞻仰了传说中的Vincent，小哥儿比我还胖，我很欣慰。在Twitter上看到了&lt;a href="http://blog.linjian.org/"&gt;林健&lt;/a&gt;桑拍的热舞照片，感觉他坐得离我不远，把坐我前面的都遍历了一遍却没找到，谁知道居然在我后面。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Navicat: 轻量的多数据库客户端</title><link>http://0x3f.org/posts/navicat-a-light-weight-database-client/</link><pubDate>Wed, 06 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/navicat-a-light-weight-database-client/</guid><description>&lt;p&gt;&lt;a href="http://www.navicat.com/en/"&gt;Navicat&lt;/a&gt;是一套商业软件，但是它的免费版Navicat Lite已足够好用。作为一套数据库客户端，它具有以下特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持Microsoft SQL Server、Oracle、MySQL、PostgreSQL、SQLite五个最常见的关系数据库。&lt;/li&gt;
&lt;li&gt;占用系统资源少，轻便快捷&lt;/li&gt;
&lt;li&gt;功能较为全面，使用方便&lt;/li&gt;
&lt;li&gt;跨平台&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我使用Navicat完成一般的数据库操作，这样可以无须在多种数据库的官方客户端之间来回切换，而且对于速度不快的机器来说，Navicat轻量的优势是很明显的。&lt;/p&gt;
&lt;p&gt;Navicat另外一个为人所忽略的优点是对SQLite的支持，我曾花不少时间找一个好的SQLite的客户端，大部分搜索结果都介绍的是另外一个&lt;a href="http://sqliteman.com/"&gt;Sqliteman&lt;/a&gt;，但是我始终不能习惯它，感觉这个东西功能少而且不好用。直到发现Navicat，才算找到一个完善的SQLite客户端。&lt;/p&gt;
&lt;p&gt;对于跨平台的特性，Navicat对Linux平台的支持其实是通过wine实现的，好在其安装包对wine已做过定制，运行状况良好。&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>从iG:Syntax Hiliter转换到WP-Syntax</title><link>http://0x3f.org/posts/migrate-from-igsyntax-hiliter-to-wp-syntax/</link><pubDate>Wed, 06 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/migrate-from-igsyntax-hiliter-to-wp-syntax/</guid><description>&lt;p&gt;终于决定放弃使用了&lt;a href="http://0x3f.org/?p=342"&gt;三年多&lt;/a&gt;的iG:Syntax Hiliter，将代码语法高亮插件换成&lt;a href="http://wordpress.org/extend/plugins/wp-syntax/"&gt;WP-Syntax&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;原因是Vim的Markdown语法高亮&lt;a href="http://www.vim.org/scripts/script.php?script_id=2882"&gt;插件&lt;/a&gt;有问题，会把iG的标签&lt;code&gt;[LANG]&lt;/code&gt;当作Markdown的超链接处理，结果导致插入代码后，后面的内容被错误地著色，很难看。而Syntax使用&lt;code&gt;&amp;lt;pre lang="LANG"&amp;gt;&lt;/code&gt;格式的标签，不会有这个问题。&lt;/p&gt;
&lt;p&gt;其实很早就想过要换了，只是受累于使用iG进行高亮的文章太多，替换起来不方便。加上后来&lt;a href="http://0x3f.org/?p=501"&gt;解决&lt;/a&gt;了由于iG停止更新导致的不支持更多的语法的问题，所以就一致拖到现在。今天晚上花了一个小时就完成了替换，比想象中的要容易地多。&lt;/p&gt;
&lt;p&gt;根据我使用过的语法的情况，使用以下语句在数据库中替换iG的标签到Syntax的标签：&lt;/p&gt;
```sql
update wp_posts set post_content=replace(post_content,'[bash]','&amp;lt;pre lang="bash" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/bash]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[python]','&amp;lt;pre lang="python" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/python]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[vim]','&amp;lt;pre lang="vim" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/vim]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[java]','&amp;lt;pre lang="java" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/java]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[lua]','&amp;lt;pre lang="lua" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/lua]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[sql]','&amp;lt;pre lang="sql" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/sql]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[plsql]','&amp;lt;pre lang="plsql" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/plsql]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[php]','&amp;lt;pre lang="php" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/php]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[cpp]','&amp;lt;pre lang="cpp" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/cpp]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[inno]','&amp;lt;pre lang="inno" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/inno]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[xml]','&amp;lt;pre lang="xml" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/xml]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[html]','&amp;lt;pre lang="html4strict" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/html]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[ini]','&amp;lt;pre lang="ini" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/ini]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[pascal]','&amp;lt;pre lang="pascal" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/pascal]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[javascript]','&amp;lt;pre lang="javascript" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/javascript]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[reg]','&amp;lt;pre lang="reg" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/reg]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'[css]','&amp;lt;pre lang="css" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'[/css]','&amp;lt;/pre&amp;gt;');
update wp_posts set post_content=replace(post_content,'&amp;lt;coolcode LANG="php"&amp;gt;','&amp;lt;pre lang="php" line="1"&amp;gt;');
update wp_posts set post_content=replace(post_content,'&amp;lt;/coolcode&amp;gt;','&amp;lt;/pre&amp;gt;');
```
&lt;p&gt;即便转换到Syntax，也不能避免Vim中Markdown语法高亮的问题，只要文字中出现成对的方括号，仍然会出问题，正确的做法是对HTML标签中的内容不进行Markdown语法的著色。&lt;/p&gt;</description></item><item><title>Orta: 凸凹有致的GTK主题</title><link>http://0x3f.org/posts/orta-a-pretty-gtk-theme/</link><pubDate>Tue, 05 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/orta-a-pretty-gtk-theme/</guid><description>&lt;p&gt;如果说&lt;a href="http://skiesofazel.deviantart.com/art/Orta-184118297"&gt;Orta&lt;/a&gt;最大的特点，就是凸凹有致。它的主要组件都突出了这个特点，加上对细节的表现很细致，整个主题给人以很舒服的感觉。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/wwLFAQ5QZ1dR1UrhYYdxZA?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/_ceUJ_lBTHzc/TZk3aLmNBTI/AAAAAAAABno/dOle8elWvtA/s800/2011-04-04.11%3A20%3A09.Gtk%2B%202.0%20Change%20Theme.01.png" height="474" width="413" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>在非GNOME环境中使用TweetDeck</title><link>http://0x3f.org/posts/howto-use-tweetdeck-out-of-gnome/</link><pubDate>Tue, 05 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-use-tweetdeck-out-of-gnome/</guid><description>&lt;p&gt;在非GNOME桌面环境中，运行TweetDeck会报如下错误：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ooops, TweetDeck can't find your data
TweetDeck is having trouble using some of your passwords that are stored securely on your machine. Clicking submit will clear this data so that you continue to use TweetDeck.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原因是Adobe Air将密码保存在GNOME的Keyring里，而此时Air找不到GNOME的相关守护进程&lt;strong&gt;gnome-keyring-daemon&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;使用如下脚本启动之：&lt;/p&gt;
&lt;p&gt;
```bash
#!/bin/bash
GNOME_KEYRING=`pidof gnome-keyring-daemon`
GNOME_DESKTOP_SESSION_ID=$GNOME_KEYRING /usr/bin/tweetdeck &amp;
```
&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Soothe: 柔和细致的GTK主题</title><link>http://0x3f.org/posts/gtk-theme-soothe/</link><pubDate>Sat, 02 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/gtk-theme-soothe/</guid><description>&lt;p&gt;&lt;a href="http://lassekongo83.deviantart.com/art/Soothe-199342656"&gt;Soothe&lt;/a&gt;给人的感觉是细致而且柔和，不易于产生视觉疲劳，这正对我的胃口。更完美的是，它支持虚线焦点框，对于喜欢使用键盘的Rox-filer重症患者来说很重要。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/MvcanM-ssxnIsXgEMvfmaA?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/_ceUJ_lBTHzc/TZk3aFUwttI/AAAAAAAABnk/ncEW0uYbqJM/s800/2011-04-04.11%3A17%3A30.Gtk%2B%202.0%20Change%20Theme.01.png" height="474" width="411" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Posted via &lt;a href="http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/"&gt;UltraBlog.vim&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>UltraBlog.vim: Ultimate Vim Blogging Plugin</title><link>http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/</link><pubDate>Sat, 02 Apr 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ultrablog-as-an-ultimate-vim-blogging-plugin/</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;UltraBlog.vim is yet another Vim blogging script for Wordpress.&lt;/p&gt;
&lt;p&gt;The biggest difference between UB and other similar scripts is that UB is an ultimate client, which stores posts locally in an SQLite database, while others just operate remotely. In this way, many things can be done easily by the advantage of local storage and many other utilities, for example, you can search for posts stored in the database with a few keywords by typing a simple command, also you can preview drafts with any of your favorite templates as soon as you want to.&lt;/p&gt;</description></item><item><title>解决gVim白边问题的伪方法</title><link>http://0x3f.org/posts/the-fake-way-to-fix-white-gap-of-gvim/</link><pubDate>Mon, 21 Mar 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/the-fake-way-to-fix-white-gap-of-gvim/</guid><description>&lt;p&gt;gVim的窗口大小与行数、列数、字体宽度等都有关系，并不像一般的图形界面一样可以完全地最大化或全屏，如果几个因素组合后与屏幕分辨率不符合，就会在屏幕的左边和底部出现灰色的白边。&lt;/p&gt;
&lt;p&gt;这是gVim非常著名的一个问题，它使最大化的gVim窗口显得非常难看。目前仅有一种变通的解决方法，就是把白边部分的颜色设置成和gVim主题背景色一致的颜色：&lt;/p&gt;
&lt;p&gt;
```bash
# 修改~/.gtkrc-2.0，加入如下内容：
style "vimfix" {
bg[NORMAL] = "#DBDBD2" # this matches my gvim theme 'Normal' bg color.
}
widget "vim-main-window.*GtkForm" style "vimfix"
```
&lt;/p&gt;
&lt;p&gt;由于并非真正地去掉白边，所以只能算是个伪方法。&lt;/p&gt;
&lt;p&gt;Windows下的方法见&lt;a href="../fullscreen-for-gvim-on-windows/"&gt;这里&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>Batch Cat v0.3 Released</title><link>http://0x3f.org/posts/batchcat-v03-released/</link><pubDate>Sun, 20 Mar 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/batchcat-v03-released/</guid><description>&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/bqYPszwt0P7OI9snKxv3WA?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TIIMnE-09dI/AAAAAAAABdk/q_hDtyXJozo/s800/wp-batch-cat.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Change Log&lt;/h3&gt;
&lt;blockquote&gt;
&lt;strong&gt;2011-03-20 Sunday&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Solve the compatibility &lt;a href="http://wordpress.org/support/topic/plugin-batch-cat-doesnt-work-for-31"&gt;problem&lt;/a&gt; under Wordpress 3.1, thanks to &lt;a href="http://coliq.wongkediri.com/batch-cat-wordpress-plugin-not-working-fixed.html"&gt;wongkediri&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check &lt;a href="http://0x3f.org/?p=1603"&gt;the plugin&amp;rsquo;s page&lt;/a&gt; for more information.&lt;/p&gt;</description></item><item><title>使用Vim写博客</title><link>http://0x3f.org/posts/blogging-with-vim/</link><pubDate>Sat, 19 Mar 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/blogging-with-vim/</guid><description>&lt;p&gt;&lt;a href="http://www.vim.org/scripts/script.php?script_id=3510"&gt;VimRepress&lt;/a&gt;是Vim写博客的插件中较新的一个，是久未更新的&lt;a href="http://www.vim.org/scripts/script.php?script_id=1953"&gt;Vimpress&lt;/a&gt;的一个衍生版。&lt;/p&gt;
&lt;p&gt;虽然不是所有此类插件中功能最多的一个，但VimRepress非常实用，除包含最常用的几个功能外，还支持&lt;a href="http://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt;。但是当前版本的VimRepress在转换Markdown格式的字符串到HTML时，是通过直接调用外部命令&lt;strong&gt;markdown&lt;/strong&gt;来实现的，这显然只是针对Linux（及其它类UNIX）系统设计的。&lt;/p&gt;
&lt;p&gt;为了使VimRepress支持在Windows下使用Markdown写文章，可以对它做一些改进。&lt;/p&gt;
&lt;p&gt;修改VimRepress的源文件&lt;strong&gt;blog.vim&lt;/strong&gt;，在&lt;code&gt;if __name__ == "__main__":&lt;/code&gt;这一行的上方加入如下两个函数：&lt;/p&gt;
&lt;p&gt;
```python
def markdown_preview2():
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import markdown2 as mkd
global vimpress_temp_dir
if vimpress_temp_dir == '':
vimpress_temp_dir = tempfile.mkdtemp(suffix="vimpress")
temp_htm = os.path.join(vimpress_temp_dir, "vimpress_temp.htm")
html_heads = \
"""&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"&gt;
&lt;/head&gt;
&lt;body&gt;
"""
tmp_file = open(temp_htm, 'w')
tmp_file.write(html_heads)
txt = "\n".join(vim.current.buffer[:])
#txt = unicode(txt,'cp936')
tmp_file.write(mkd.markdown(txt))
#tmp_file.write(mkd.markdown("\n".join(vim.current.buffer[:])))
tmp_file.close()
webbrowser.open("file://%s" % temp_htm)
def markdown_newpost2():
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import markdown2 as mkd
global vimpress_temp_dir
if vimpress_temp_dir == '':
vimpress_temp_dir = tempfile.mkdtemp(suffix="vimpress")
temp_htm = os.path.join(vimpress_temp_dir, "vimpress_post.htm")
title = ""
title_s = 0
try:
while title_s &lt; 10:
if vim.current.buffer[title_s].startswith("#"):
title = vim.current.buffer[title_s].strip('#')
break
title_s += 1
except IndexError:
pass
cur_file = vim.eval('expand("%:p")')
if cur_file is None:
cur_file = os.path.join(vimpress_temp_dir, "tmp_vimpress.mkd")
sys.stdout.write("\n\nCurrent buffer saved to %s\n\n" % cur_file)
vim.command(":w! %s" % cur_file)
tmp_file = open(temp_htm, 'w')
tmp_file.write(mkd.markdown("\n".join(vim.current.buffer[:])))
tmp_file.close()
sys.stdout.write("Press ENTER to continue.")
vim.command(":bdelete")
vim.command(":r %s" % temp_htm)
blog_new_post(title = title)
```
&lt;/p&gt;</description></item><item><title>修改Vimball默认安装路径</title><link>http://0x3f.org/posts/howto-set-the-default-vimball-install-path/</link><pubDate>Sat, 19 Mar 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-set-the-default-vimball-install-path/</guid><description>&lt;p&gt;在Windows下，我希望把vba文件安装到$VIM/vimfiles目录下，而不是用户主目录中。&lt;/p&gt;
&lt;p&gt;Vim在安装vba文件时默认从$VIMRUNTIME中取出第一个路径作为安装路径，使用如下命令查看当前设置：&lt;/p&gt;
&lt;p&gt;
```vim
:echo &amp;rtp
```
&lt;/p&gt;
&lt;p&gt;在Windows下，Vim默认将用户主目录放在了$VIMRUNTIME的第一个，因此才会将vba安装到用户主目录。&lt;/p&gt;
&lt;p&gt;修改方法为在vimrc中加入如下设置：&lt;/p&gt;
&lt;p&gt;
```vim
set rtp-=$HOME/vimfiles
```
&lt;/p&gt;</description></item><item><title>Dumperor v1.0.0 Released</title><link>http://0x3f.org/posts/dumperor-v100-released/</link><pubDate>Tue, 15 Mar 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/dumperor-v100-released/</guid><description>&lt;h3&gt;Changelog&lt;/h3&gt;
&lt;blockquote&gt;
&lt;strong&gt;2011-03-14&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Now Dumperor is stable enough.&lt;/li&gt;
&lt;li&gt;Add the abillity to export table structures or data to a human readable format, which is suit for comparing.&lt;/li&gt;
&lt;li&gt;Add the abillity to manage multiple configurations.&lt;/li&gt;
&lt;li&gt;Add a desktop application to sort the human readable output file of table structures, written in python and tk.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check the &lt;a href="http://0x3f.org/?p=1617"&gt;main page&lt;/a&gt; for more information.&lt;/p&gt;</description></item><item><title>刷了Oxygen v2.0.1</title><link>http://0x3f.org/posts/flashed-oxygen-v201/</link><pubDate>Sun, 06 Mar 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/flashed-oxygen-v201/</guid><description>&lt;p&gt;上周 Oxygen v2.0 发布之后，感觉还不稳定，忍住了。前两天终于刷上了刚发布的 Oxygen v2.0.1 。&lt;/p&gt;
&lt;p&gt;事先直接做了一次完整的擦除，刷完后没发现 XDA 上乱七八糟的问题。用了两天，除了 UI 的变化，没看出来跟以前版本有什么不同，只是仍未实现轨迹球唤醒这点很遗憾。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/C-dYsOdeOj-iYlIZm_l8IA?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/_ceUJ_lBTHzc/TXOfYdamg3I/AAAAAAAABmc/F_2AXlKogkA/s400/snap20110306_223834.png" height="400" width="240" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>好贵的套啊</title><link>http://0x3f.org/posts/expensive-kindle-cover/</link><pubDate>Mon, 28 Feb 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/expensive-kindle-cover/</guid><description>&lt;p&gt;把淘宝上价格比较靠谱的几家问了个遍，都没有货，估计都是因为价格高，只代购，不存货。最后还是在买Kindle的店等了好几天才搞到了原装黑色皮套，虽然相对已经算是低价，还是十分地肉疼。&lt;/p&gt;
&lt;p&gt;无图无真相：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/mSN41KmfWQKYLFvQ0h014g?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/_ceUJ_lBTHzc/TWueBePKfoI/AAAAAAAABlU/4wf8o37uZ1A/s400/C360_2011-02-28%2020-51-59.jpg" height="267" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/tiQUWUaArTyClLcSZkdCZg?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/_ceUJ_lBTHzc/TWueCzrD5AI/AAAAAAAABlY/XcSP3X0U87M/s400/C360_2011-02-28%2020-53-05.jpg" height="267" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Anti Artificial Spam v0.2 Released</title><link>http://0x3f.org/posts/anti-artificial-spam-v02-released/</link><pubDate>Thu, 24 Feb 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/anti-artificial-spam-v02-released/</guid><description>&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/jrOJUT0rqkBrzPsVM4k4EA?feat=embedwebsite"&gt;&lt;img src="https://lh4.googleusercontent.com/_ceUJ_lBTHzc/TWZX7Vkc9qI/AAAAAAAABkg/BUMJWsLaqWA/s800/wp-anti-artificial-spam.png" height="106" width="345" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Change Log&lt;/h3&gt;
&lt;blockquote&gt;
&lt;strong&gt;2011-02-23 Wednesday 22:24:12&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Rename anti-manpower-spam to anti-artificial-spam.&lt;/li&gt;
&lt;li&gt;Don't just test if the URL is in the banned ones, but also test if it is a substring of one of them.&lt;/li&gt;
&lt;li&gt;Optimize the speed of matching.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check &lt;a href="http://0x3f.org/?p=1293"&gt;the plugin&amp;rsquo;s page&lt;/a&gt; for more information.&lt;/p&gt;</description></item><item><title>初入Kindle DX Graphite</title><link>http://0x3f.org/posts/got-kindle-dxg/</link><pubDate>Sun, 20 Feb 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/got-kindle-dxg/</guid><description>&lt;p&gt;垂涎已久，昨天终于出手，今天上午就收到了。&lt;/p&gt;
&lt;p&gt;把玩了一下自带的系统，用免费的3G网络看Wikipedia，体验不错。中文文件名不能显示，嵌入了中文字体的PDF可以正常显示。买DXG的目的就是为了看计算机类的英文PDF和繁体竖排的扫描版的古籍PDF，所以不折腾，直接装多看系统。&lt;/p&gt;
&lt;p&gt;多看果然给力，全中文界面，中文输入法，中文TTS语音朗读，而且支持MP3播放、图片浏览和包括chm、epub在内的多种电子书格式。因为暂时用不上，所以先不深究。连到Arch传PDF，直接自动挂载并弹出Nautilus，没想到对Linux如此友好！&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/QiUW7raz-GRIIAHY6ExhGg?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/_ceUJ_lBTHzc/TWEYsx6aK_I/AAAAAAAABjw/zhEKpfsTGEs/s400/C360_2011-02-20%2021-22-34.jpg" height="400" width="267" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/Gsdt90fZObxY1siONP8RBQ?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/_ceUJ_lBTHzc/TWEZHhvqyuI/AAAAAAAABj0/o9e0BhrS9mo/s400/C360_2011-02-20%2021-23-15.jpg" height="400" width="267" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;贴了膜，所以有反光，但是只要没有灯光直射，大角度效果依然良好：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/eZQCdCXnRJ9bvxeEf4HXdg?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/_ceUJ_lBTHzc/TWEZH4lMbPI/AAAAAAAABj4/QPTOixm9gbU/s400/C360_2011-02-20%2021-21-33.jpg" height="267" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;来个微距：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/y192tUMfE2zZfTEWmuCQVQ?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/_ceUJ_lBTHzc/TWEZH6AcODI/AAAAAAAABj8/_xOmnTnj0UQ/s400/C360_2011-02-20%2021-20-50.jpg" height="267" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以上图片出自G7+Camera360，光线不好，马马虎虎。&lt;/p&gt;
&lt;p&gt;缺点。一是不支持触摸操控，加上官方系统古板、笨拙，做一些高级操作是很费力的，好在多看系统在这一点上做得很好。二是PDF翻页的时候速度确实比较慢，还要闪一下屏，不过还可以接受。多看系统也不完美，最要命的是不支持3G网络，要使用3G网络还得切换到官方系统中；另外就是不支持重力感应，文档方向需要手工设置。&lt;/p&gt;
&lt;p&gt;齐活了，从此不用再担心长时间在电脑上看OReilly累眼了，也不用发愁中华书局的扫描版史书没法看了。&lt;/p&gt;</description></item><item><title>精美的图标主题：Faenza</title><link>http://0x3f.org/posts/icon-theme-faenza/</link><pubDate>Sat, 19 Feb 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/icon-theme-faenza/</guid><description>&lt;p&gt;&lt;a href="http://tiheum.deviantart.com/art/Faenza-Icons-173323228"&gt;Faenza Icons Theme&lt;/a&gt;是适用于GTK+环境的一套图标主题，风格很漂亮，而且齐全。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://picasaweb.google.com/lh/photo/oR3thuG4Fu9kHj_9JE6l5g?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/_ceUJ_lBTHzc/TV8kBGrLlFI/AAAAAAAABjc/NCuw2C_QaHk/s400/faenza_icons_by_tiheum-d2v6x24.png" height="300" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>MySQL升级后执行mysql_upgrade</title><link>http://0x3f.org/posts/execute-mysql-upgrade-after-upgrading/</link><pubDate>Fri, 11 Feb 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/execute-mysql-upgrade-after-upgrading/</guid><description>&lt;p&gt;最近把MySQL从5.1升级到5.5，之后创建存储过程时报如下错误：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;ERROR 1548 (HY000) at line 5: Cannot load from mysql.proc. The table is probably corrupted&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;解决办法是执行如下命令：
```bash
mysql_upgrade -p
```
&lt;a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-upgrade.html" target="_blank"&gt;mysql_upgrade&lt;/a&gt;是MySQL提供的一个指令，作用是检查MySQL中的各个表与当前版本的数据库是否匹配并尝试修复所有发现的问题。MySQL官方文档中推荐在每次升级后执行一下这个指令。&lt;/p&gt;</description></item><item><title>部分无线路由导致Wordpress无法登录</title><link>http://0x3f.org/posts/wordpress-fails-logging-in-with-some-wifi-routers/</link><pubDate>Mon, 31 Jan 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/wordpress-fails-logging-in-with-some-wifi-routers/</guid><description>&lt;p&gt;问题表现为在登录页面输入用户名和密码并点击登录按钮后，Wordpress跳转到登录页面。&lt;/p&gt;
&lt;p&gt;解决方法是修改&lt;strong&gt;&lt;em&gt;wp-includes/plugable.php&lt;/em&gt;&lt;/strong&gt;中的&lt;strong&gt;&lt;em&gt;wp_set_auth_cookie()&lt;/em&gt;&lt;/strong&gt;函数，将下面这行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;setcookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$auth_cookie_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$auth_cookie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$expire&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ADMIN_COOKIE_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;COOKIE_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$secure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;改成：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;setcookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$auth_cookie_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$auth_cookie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$expire&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SITECOOKIEPATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;COOKIE_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$secure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这一行在这个函数中有两处，是根据php的版本决定执行哪一块，所以应该根据自己的情况修改，或者干脆两处都修改。&lt;/p&gt;
&lt;p&gt;在我的tp-link tl-wr841n中发现这个问题，而中兴无线猫中没有这个问题。&lt;/p&gt;</description></item><item><title>读完Agile Web Application Development with Yii1.1 and PHP5</title><link>http://0x3f.org/posts/after-reading-agile-web-application-development-with-yii11-and-php5/</link><pubDate>Mon, 24 Jan 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-agile-web-application-development-with-yii11-and-php5/</guid><description>&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/UbKjF4vtCfgJnNA1L7g04w?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/TT1ktv2GLvI/AAAAAAAABjA/MIM7i3CQjxk/s400/cover.jpg" height="400" width="324" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;花了两个周末，读完了&lt;em&gt;Agile Web Application Development with Yii1.1 and PHP5&lt;/em&gt;，边读边做，受益匪浅。&lt;/p&gt;
&lt;p&gt;这本书从零开始细致地讲解了用Yii开发一个项目管理系统&lt;em&gt;TrackStar&lt;/em&gt;的全过程，涉及到Yii的大部分主要特性。全书风格简洁凝练，没有过多的占用篇幅的截图，但讲解浅显易懂，可操作性很强，是我看过的&lt;strong&gt;Tutorial&lt;/strong&gt;类的书里面最好的一本。&lt;/p&gt;
&lt;p&gt;从这段时间学习Yii的体会中，我觉得在目前的条件下，对于有PHP程序开发基础的人，学习路线应该是：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.yiiframework.com/doc/guide/"&gt;Yii权威指南&lt;/a&gt;→&lt;a href="http://www.yiiframework.com/doc/blog/"&gt;The Yii Blog Tutorial&lt;/a&gt;→Agile Web Application Development with Yii1.1 and PHP5&lt;/p&gt;</description></item><item><title>Console2：取代cmd.exe的Windows虚拟终端</title><link>http://0x3f.org/posts/console2-as-an-alternative-of-cmd-exe/</link><pubDate>Sat, 22 Jan 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/console2-as-an-alternative-of-cmd-exe/</guid><description>&lt;p&gt;相对于鸡肋cmd.exe，&lt;a href="http://sourceforge.net/projects/console/"&gt;Console2&lt;/a&gt;有以下优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;窗口大小可调整&lt;/li&gt;
&lt;li&gt;字体样式可选择&lt;/li&gt;
&lt;li&gt;支持多标签&lt;/li&gt;
&lt;li&gt;有很方便的选择、复制、粘贴等基本编辑功能&lt;/li&gt;
&lt;li&gt;支持自定义快捷键&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对经常不得不使用Windows虚拟终端的人来说，以上几个特性足以使人忘掉cmd.exe。其实，Console2本身只是Shell的图形前端，只是在默认情况下它会调用cmd.exe处理用户输入，因此，也可以通过设置使Console2成为Cygwin的前端，只是从这一点上讲，Console2和&lt;a href="http://code.google.com/p/mintty/"&gt;Mintty&lt;/a&gt;相比完全没有优势。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/hfesI_yiNpTZ68BKIqdImA?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/TTotT9zYK6I/AAAAAAAABi0/Qzv4d2Abe-g/s400/console2.png" height="332" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Dokan SSHFS：Windows下通过SSH挂载Linux主机为本地分区</title><link>http://0x3f.org/posts/mount-linux-dirs-as-windows-local-partitions/</link><pubDate>Thu, 20 Jan 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/mount-linux-dirs-as-windows-local-partitions/</guid><description>&lt;p&gt;Linux一般使用Samba向Windows共享资源。另一个办法就是使用SSH。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://dokan-dev.net/en/"&gt;Dokan&lt;/a&gt;是一个为Windows提供实现新文件系统的开发库，而&lt;a href="http://dokan-dev.net/en/download/#sshfs"&gt;Dokan SSHFS&lt;/a&gt;是在此基础上实现的挂载SSH通道为本地分区的文件系统。必须先安装Dokan，然后再安装Dokan SSHFS。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/d6J9vTU8cvK2KEplEo0ZaQ?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_ceUJ_lBTHzc/TThWJn7FrzI/AAAAAAAABic/Et7kroeInF8/s400/sshfs.png" height="338" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如果从安装SSH服务做起，步骤是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在Linux主机上安装openssh&lt;/li&gt;
&lt;li&gt;修改Linux主机的&lt;strong&gt;/etc/hosts.allow&lt;/strong&gt;，加入&lt;code&gt;sshd: ALL&lt;/code&gt;，以允许外部访问&lt;/li&gt;
&lt;li&gt;启动sshd守护进程&lt;/li&gt;
&lt;li&gt;在Windows主机上安装Dokan和Dokan SSHFS&lt;/li&gt;
&lt;li&gt;通过SSHFS的图形配置工具挂载SSH通道&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这种方式的好处是简单，但是存在安全隐患，不管怎样，公布SSH连接绝非好事，这意味著接入用户可以远程控制Linux主机，尤其是当SSH账户的权限较高时。因此，这种方式只适用于虚拟机或家庭网络，例如对Host-Guests共享支持不佳的KVM虚拟机来说就是个好的选择。即便如此，也要注意相应的Windows主机的安全防范，否则，入侵者可以通过Windows主机做跳板来进入Linux主机。&lt;/p&gt;</description></item><item><title>读完《程序员修炼之道》</title><link>http://0x3f.org/posts/after-reading-pragmatic-programmers/</link><pubDate>Tue, 11 Jan 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-pragmatic-programmers/</guid><description>&lt;p&gt;上周日读完了这本&lt;strong&gt;&lt;em&gt;The Pragmatic Programmer&lt;/em&gt;&lt;/strong&gt;的中译本，都是经验之谈，有些东西读后受益匪浅，更多的需要时间去体会。&lt;/p&gt;
&lt;p&gt;很纠结读的是中译本，但实在买不到原版，非常好奇他们是怎样地殚精竭虑才能想出如此烂俗的译名。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/jtr_krg4zxuQ2SjAY6_msw?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_ceUJ_lBTHzc/TSxhb6t4awI/AAAAAAAABiQ/YDce_zvQreQ/s400/%E7%A8%8B%E5%BA%8F%E5%91%98%E4%BF%AE%E7%82%BC%E4%B9%8B%E9%81%93_crop1.jpg" height="400" width="302" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Oracle中对LOB字段的操作方法</title><link>http://0x3f.org/posts/oracle-lob-operations/</link><pubDate>Fri, 07 Jan 2011 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/oracle-lob-operations/</guid><description>&lt;p&gt;在Oracle中插入或更新LOB字段时，可以将字符串以如下方式写入SQL语句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tbl_lob&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fld_lob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utl_raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cast_to_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这样做的限制是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Oracle中单条SQL语句有长度限制&lt;/li&gt;
&lt;li&gt;cast_to_raw()对字符串有长度限制&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此如果要插入或更新的字符串过长，会导致执行失败。此时应该使用dbms_lob处理LOB相关字段。下面是利用dbms_lob更新一个BLOB字段的存储过程，对CLOB的操作同理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;replace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;procedure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;updateblob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctbl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;varchar2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cfld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;varchar2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cstr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;varchar2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ccond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;varchar2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vqry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;varchar2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vblob&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vbatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;varchar2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vstrlen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;voffset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vamt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;begin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vstrlen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cstr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vqry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;update &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;ctbl&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; set &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;cfld&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;=empty_blob() where &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;ccond&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;execute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;immediate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vqry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vqry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;select &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;cfld&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; from &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;ctbl&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; where &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;ccond&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; for update&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;execute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;immediate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vqry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vblob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vstrlen&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;vamt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vstrlen&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;voffset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vbatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cstr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;voffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vamt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;voffset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;voffset&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;vamt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbms_lob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeappend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vblob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vbatch&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utl_raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cast_to_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vbatch&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbms_lob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeappend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vblob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cstr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utl_raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cast_to_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cstr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;示例：&lt;/p&gt;</description></item><item><title>darkstat: 网络流量监测工具</title><link>http://0x3f.org/posts/darkstat-as-a-network-discharge-meter/</link><pubDate>Sun, 26 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/darkstat-as-a-network-discharge-meter/</guid><description>&lt;p&gt;&lt;a href="http://dmr.ath.cx/net/darkstat/"&gt;darkstat&lt;/a&gt;是一个跨平台的网络流量监测工具，可显示最大一个月内操作系统的各项网络流量指标。&lt;/p&gt;
&lt;p&gt;具有以下特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;以守护进程方式运行，提供Web用户界面，零配置，易于使用&lt;/li&gt;
&lt;li&gt;可显示较为详细的网络流量指标&lt;/li&gt;
&lt;li&gt;性能表现好，占用资源少&lt;/li&gt;
&lt;li&gt;跨平台，支持多个UNIX、类UNIX操作系统，并有非官方的Windows移植版&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;具有以下不足：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;功能较为简单，以易用性换灵活性&lt;/li&gt;
&lt;li&gt;日志记录功能比较单薄，需要编写辅助脚本并设置定时任务&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;darkstat启动时需要手工指定监视的网络接口，因此需要用根权限启动：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo darkstat -i eth0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;darkstat默认使用&lt;strong&gt;667&lt;/strong&gt;端口提供Web访问，可以用&lt;strong&gt;-p&lt;/strong&gt;参数指定端口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo darkstat -i eth0 -p &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;darkstat的Web用户界面分为Graph、Hosts和Host三部分。Graph是缺省主页，用于显示最近一分钟、一小时、一天和一个月的流量统计直方图，将光标置于任何一个直方条上可查看对应时刻的流量指标：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/NAB3_2TtnezdM45HoNd5pQ?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_ceUJ_lBTHzc/TRcCUWqnF0I/AAAAAAAABhs/wLRQb3rvHW8/s400/darkstat-graphs.png" height="400" width="395" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hosts界面按主机显示各自的流量统计指标的值：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/kG1J2j2eecaLUnhDL-fArA?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_ceUJ_lBTHzc/TRcCUXxnsMI/AAAAAAAABhw/ri5OsbqPdmc/s400/darkstat-hosts.png" height="322" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;单击Hosts界面上的IP进入对应主机的Host界面，此界面按TCP/UDP类型显示对应的主机的各端口的网络流量指标的值：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/XBNQWty4lp63OWwyAFm_BA?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TRcCUn6lg_I/AAAAAAAABh0/6Aj0hArzIYk/s800/darkstat-host.png" height="800" width="190" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;可通过如下命令查看占用指定端口的进程：&lt;/p&gt;
&lt;blockquote&gt;
[lenin@archer ~]$ lsof -i tcp:58062 -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mlnet 18660 lenin 74u IPv4 251788 0t0 TCP 192.168.1.3:58062-&gt;122.116.212.89:http (ESTABLISHED)
&lt;/blockquote&gt;
&lt;p&gt;darkstat区别于其它流量监测工具的最大的优点就是简单易用，非常适合对流量监测应用不复杂的场景。前段时间公司的一台RHEL服务器因为流量过大多次被网管拔线，后来用darkstat监测到大部分流量被几个UDP端口占去，进而发现原来是服务器被入侵并被安装了一个扫描器&lt;a href="http://code.google.com/p/sipvicious/"&gt;SIPVicious&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>Linux的内存使用机制</title><link>http://0x3f.org/posts/linux-memory-usage/</link><pubDate>Fri, 24 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/linux-memory-usage/</guid><description>&lt;p&gt;在top中，内存使用情况显示为如下格式：&lt;/p&gt;
&lt;blockquote&gt;
Mem: 3056828k total, 2624472k used, 432356k free, 185196k buffers
Swap: 2096476k total, 0k used, 2096476k free, 1613592k cached
&lt;/blockquote&gt;
&lt;p&gt;根据内存的使用情况，将内存空间划分为四种类型：已使用（used），未使用（free），缓冲区（buffers）和已缓存（cached）。&lt;/p&gt;
&lt;p&gt;“已使用”是指目前正被使用的活跃的内存区域。“未使用”是指当前空闲的内存区域。“缓冲区”是用于存放即将写入存储介质的数据的区域。“已缓存”是指曾因需要而被读入内存、但目前已不被使用的数据。Linux通常会在资源使用完毕后保留一部分数据在内存中而不全部释放，这就是“已缓存”区域，这样当这些数据再次被使用时，系统就可以直接从内存中读取。而“缓冲区”用于将对存储介质的写操作集中进行。因此，“缓冲区”和“已缓存”特性对减少存储介质IO和加速系统运行都具有非常重要的作用。&lt;/p&gt;
&lt;p&gt;所以，Linux运行一段时间后，通常看起来空闲内存都很小，其实是因为很大一部分被用作“已缓存”区域，这部分内存会在内存资源紧张时被自动释放，也可以通过如下命令手工释放：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &amp;gt; /proc/sys/vm/drop_caches
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Vim中设置关键词识别规则的方法</title><link>http://0x3f.org/posts/howto-set-keyword-identification-in-vim/</link><pubDate>Wed, 22 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-set-keyword-identification-in-vim/</guid><description>&lt;p&gt;在Vim中，关键词是一个至关重要的概念。合理地利用关键词，可以快速地对光标下有特殊含义的字符串进行一系列的操作，例如通过快捷键复制关键词、查询函数定义或文档、在项目中查询所有引用当前函数的地方等等。这对工作效率的提升有极大的帮助。&lt;/p&gt;
&lt;p&gt;但我的Vim对PHP文件的关键词识别有问题，在选择函数名的时候总是将函数名后的小括弧一起选入。&lt;/p&gt;
&lt;p&gt;Vim使用选项iskeyword设定关键词的匹配规则，使用如下命令查看当前文件类型的关键词规则：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;iskeyword&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;我这里查看PHP文件的规则结果如下：&lt;/p&gt;
&lt;blockquote&gt;
iskeyword=@,48-57,_,192-255,$,(
&lt;/blockquote&gt;
&lt;p&gt;不明白为什么缺省设置中会有左括弧，在vimrc中加入如下配置取消之：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;iskeyword&lt;/span&gt;&lt;span class="p"&gt;-=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Root了Desire并刷了Oxygen</title><link>http://0x3f.org/posts/rooted-desire-and-flashed-oxygen/</link><pubDate>Sun, 19 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/rooted-desire-and-flashed-oxygen/</guid><description>&lt;p&gt;五月末入手 Desire 后一直没有折腾，一是因为时间和精力不够，二也没有迫切的需要。&lt;/p&gt;
&lt;p&gt;这次 Google Map 的&lt;a href="http://android.guao.hk/posts/google-maps-5-0-for-android-coming.html"&gt;更新&lt;/a&gt;给了我足够的理由，加上 Froyo 原生的“&lt;em&gt;移动到SD&lt;/em&gt;”功能已被榨干最后一点油水，于是用 &lt;a href="http://unrevoked.com/"&gt;unrEVOked3&lt;/a&gt; 很傻瓜地 root 了 Desire ，用 Move2SD Enabler 开启了完全的 App2SD ，用 Market Enabler 化妆潜入米国菜市场安装了 Google Map 5.0 ，最后还启用了 SetCPU 。&lt;/p&gt;
&lt;p&gt;后来还是没有把持住，一不做二不休，对原装的 Sense 做了一个 nandroid 备份，刷上了 &lt;a href="http://forum.xda-developers.com/showthread.php?t=829734"&gt;Oxygen&lt;/a&gt; 。 Oxygen 的主题十分的简洁美观，我觉得比 Sense 漂亮：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/9wFenU4A3IbKivS2cGboQw?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/TQ4LVo_oUGI/AAAAAAAABg4/ecJd4sggC0A/s400/CAP201012192130.png" height="400" width="240" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oxygen 基于 &lt;a href="http://source.android.com/"&gt;AOSP&lt;/a&gt; ，是改动较少、较接近于官方Android的一个ROM，最大的优点是速度快和稳定性高。这两天使用的感受证明了这两点，尤其是速度，一骑绝尘啊，比 Sense 之流好多了。当然，因为精简，理论上在耗电量上较 Sense 要小，不过我实际感觉如果持续使用的话也好不到哪去，但是待机的话效果还是比较明显，可能跟启用了 SetCPU 也有一定的关系。&lt;/p&gt;
&lt;p&gt;开始差点刷了 &lt;a href="http://www.miui.com/"&gt;MIUI&lt;/a&gt; ，但是很多人反映有耗电和稳定性的问题。&lt;/p&gt;</description></item><item><title>Batch Cat v0.2 Released</title><link>http://0x3f.org/posts/batchcat-v02-released/</link><pubDate>Sun, 12 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/batchcat-v02-released/</guid><description>&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/bqYPszwt0P7OI9snKxv3WA?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TIIMnE-09dI/AAAAAAAABdk/q_hDtyXJozo/s800/wp-batch-cat.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Change Log&lt;/h3&gt;
&lt;blockquote&gt;
&lt;strong&gt;2010-12-12 Sunday&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Add the ability to append the selected categories to posts&lt;/li&gt;
&lt;li&gt;Add the ability to delete the selected categories from posts&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check &lt;a href="http://0x3f.org/?p=1603"&gt;the plugin&amp;rsquo;s page&lt;/a&gt; for more information.&lt;/p&gt;</description></item><item><title>Vim保存文件时移除尾行换行符的方法</title><link>http://0x3f.org/posts/howto-remove-eof-in-vim/</link><pubDate>Sun, 05 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-remove-eof-in-vim/</guid><description>&lt;p&gt;Vim认为一个文本文件的每一行都应该由一换行符结束，即使文件的最后一行也不例外。这就使得Vim保存过的文本文件在其它文本编辑器中查看时可能会在文件末尾多出一个空行。一般来说，这不是个问题，但对于程序员来说，有时候一些不规范的运行环境或其它组件就要求文件的最后一行不能有换行符，否则就会出莫名其妙的问题，尤其是在Windows环境下最常见。&lt;/p&gt;
&lt;p&gt;要在保存文件时不在最后一行添加换行符，最常见、最简单的方法就是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;noendofline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但是这样做有一个问题，就是会把DOS格式的文件自动转换成UNIX格式，WinSlave们肯定不希望这么做。&lt;/p&gt;
&lt;p&gt;因此，可在vimrc中加入如下内容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Save the current buffer as a file with no EOF sign.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;SaveAsNOEOF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;iconv(v:val,&amp;#34;&amp;#39;&lt;/span&gt;.&amp;amp;&lt;span class="nx"&gt;enc&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;&amp;#34;,&amp;#34;&amp;#39;&lt;/span&gt;.&amp;amp;&lt;span class="nx"&gt;fenc&lt;/span&gt;.&lt;span class="s1"&gt;&amp;#39;&amp;#34;) . nr2char(13)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;writefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;bufname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;nomodified&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Save the current buffer and get rid of the EOF sign.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;SaveNOEOF&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;SaveAsNOEOF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bufname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;nargs&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;SaveNOEOF&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;SaveNOEOF&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;nargs&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;SaveAsNOEOF&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;SaveAsNOEOF&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后就可以使用SaveNOEOF和SaveAsNOEOF两条命令去保存没有EOF的文件了。&lt;/p&gt;</description></item><item><title>黄粱一梦</title><link>http://0x3f.org/posts/a-fools-paradise/</link><pubDate>Sat, 04 Dec 2010 17:51:00 +0000</pubDate><guid>http://0x3f.org/posts/a-fools-paradise/</guid><description>&lt;p&gt;昨天晚上放弃了年终聚餐，去看了《黄粱梦》。&lt;/p&gt;
&lt;p&gt;一个很老套的故事，耳熟能详，但是经过精心的演绎，加上声、光、电的完美运用，真就给人以耳目一新的感觉。我一直不怎么观注地方戏曲，以往觉得能凑合听听的也就是河南的越调、安徽的黄梅戏等，河北的地方戏也就听说过一个河北梆子，像邯郸的平调落子这样的闻所未闻。《黄粱梦》彻底改变了我对地方戏曲的看法，京剧、昆曲固然高雅，但假如也加入魔术、杂技、俚语甚至RAP，肯定会让人觉得不伦不类，地方戏曲的长处就在于灵活多变，不拘泥形式，能够很快地针对时代变化作出改进，如果分寸拿捏得好，就能不断推陈出新。&lt;/p&gt;
&lt;p&gt;整场戏用两个小时的时间表现了卢生一梦中的一生，故事情节十分紧凑，每折都用不同的场景、不同的唱腔、不同的表现形式，让人眼花缭乱，一改传统戏剧连篇累牍的大段说词，整场看下来从未觉得枯燥乏味，很适应时下流行的快餐文化。在故事情节上，《黄粱梦》并没有跳出惩恶扬善、因果报应的老套，当然，一味地追求突破未见得是好事。&lt;/p&gt;
&lt;p&gt;虽然时间不长，但是整场戏有很多地方让人印象深刻，比如有句意味深长的戏词“邯郸道长，人生路短”，还有那句雷倒了无数人的“现在哪里还有什么纯真美女啊”。当然，最让人意犹未尽的还是这段高潮的“贪官舞”：&lt;/p&gt;
&lt;p&gt;&lt;embed src="http://www.tudou.com/v/anrxiFeKSfM/v.swf" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="480" height="400"&gt;&lt;/embed&gt;&lt;/p&gt;</description></item><item><title>Hope GTK：平静、柔和、细腻的主题</title><link>http://0x3f.org/posts/gtk-theme-hope/</link><pubDate>Sat, 04 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/gtk-theme-hope/</guid><description>&lt;p&gt;&lt;a href="http://0rax0.deviantart.com/art/Hope-GTK-187658025"&gt;Hope GTK&lt;/a&gt;是套漂亮的冷色调的GTK主题，色调过渡柔和，细节表现得也很好，整体给人以平静的感觉。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/4_sO8LFMCRO5xLKi6v9wQA?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_ceUJ_lBTHzc/TPpOe4PGEjI/AAAAAAAABgc/Lhir6fzkDWE/s400/hope_gtk_by_0rax0-d33q5ux.jpg" height="320" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>virtio可能导致windows蓝屏</title><link>http://0x3f.org/posts/virto-may-breakdown-windows/</link><pubDate>Sat, 04 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/virto-may-breakdown-windows/</guid><description>&lt;p&gt;前段时间突然发现kvm中的windows在启动时蓝屏，开始以为是kvm新版本的bug，后来发现如果不启用虚拟机硬盘的virtio就不会出现蓝屏。&lt;/p&gt;
&lt;p&gt;于是下载了最新版的virtio，然而更新后，蓝屏的问题并没有解决，所以目前只能暂时不使用virtio。不过网卡的virtio是没有问题的。&lt;/p&gt;</description></item><item><title>开启自定义GTK程序菜单快捷键的方法</title><link>http://0x3f.org/posts/howto-enable-hotkey-for-gtk-menus/</link><pubDate>Sat, 04 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-enable-hotkey-for-gtk-menus/</guid><description>&lt;p&gt;基于GTK的程序菜单本身支持通过在焦点所在的菜单项上按下组合键来定义该菜单项的快捷键，但默认并不开启。&lt;/p&gt;
&lt;p&gt;一般来说，对于支持X的会话管理的桌面环境，可以通过修改相应的设置来开启这个功能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GNOME中该设置项所在的路径是：主选单 &gt; 桌面 &gt; 偏好设定 &gt; 选单及功具列 &gt; 可编辑选单捷径键&lt;/li&gt;
&lt;li&gt;XFCE中该设置项所在的路径是：主选单 &gt; 设置 &gt; 外观 &gt; 设置 &gt; 开启可编辑快捷键&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于不支持会话管理的桌面环境，可在~/.gtkrc-2.0中添加如下配置内容：&lt;/p&gt;
&lt;blockquote&gt;
gtk-can-change-accels = 1
&lt;/blockquote&gt;</description></item><item><title>screen曰：$TERM too long - sorry.</title><link>http://0x3f.org/posts/screen-is-sorry-for-term-being-too-long/</link><pubDate>Wed, 01 Dec 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/screen-is-sorry-for-term-being-too-long/</guid><description>&lt;p&gt;最近rxvt-unicode-256color的一次更新触发了screen的一个缺陷。新的版本将默认的环境变量$TERM由rxvt-256color改成了rxvt-unicode-256color，这导致在rxvt中启动screen时报这样的错误：&lt;/p&gt;
&lt;blockquote&gt;
$TERM too long - sorry.
&lt;/blockquote&gt;
&lt;p&gt;虽然可以在.Xdefaults中指定$TERM的值，但是&lt;a href="https://aur.archlinux.org/packages.php?ID=13060"&gt;据说&lt;/a&gt;这样会导致rxvt加载错误的terminfo，并导致终端的颜色由256色降低到88色。另外虽然按照同样的说法，可以在screenrc中设置$TERM的值，但是不知道是我写的格式不对还是什么原因，无效。&lt;/p&gt;
&lt;p&gt;最终还是设了个别名：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# vi ~/.bashrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;screenx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;export TERM=screen-256color &amp;amp;&amp;amp; screen&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Oxygen Refit：适用于xfce的Oxygen图标集</title><link>http://0x3f.org/posts/oxygen-iconset-fit-for-xfce/</link><pubDate>Mon, 29 Nov 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/oxygen-iconset-fit-for-xfce/</guid><description>&lt;p&gt;Oxygen是KDE桌面环境中的一套著名的图标集，但是据说基于GTK的桌面环境如GNOME、XFCE等对其支持得不好，我这里在GNOME下倒没发现问题，不过在XFCE下文件夹的图标显示的是缺省的图标，不好看。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://gnome-look.org/content/show.php/Oxygen+Refit+2?content=79756"&gt;Oxygen Refit&lt;/a&gt;是针对GTK的桌面环境修改的Oxygen图标集，在XFCE下可以正常显示，但是缺点是最大分辨率只有48×48，不能显示较大的高清图标。Archlinux下可以安装AUR中的&lt;a href="http://aur.archlinux.org/packages.php?ID=18673"&gt;oxygenrefit2-icon-theme&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/cURosgqNAesp47LgLj4LpA?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/TPJ4grT0drI/AAAAAAAABf0/R22H_Nv6kbA/s400/2010-11-28.23%3A33%3A01.-usr-share-icons-oxygen-256x256-places%20%28%E9%A1%AF%E7%A4%BA%E7%B8%AE%E5%9C%96%29%20.01.png" height="249" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>WinMerge：开源的差异比较工具</title><link>http://0x3f.org/posts/winmerge-as-a-free-diff-tool/</link><pubDate>Mon, 29 Nov 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/winmerge-as-a-free-diff-tool/</guid><description>&lt;p&gt;&lt;a href="http://winmerge.org/"&gt;WinMerge&lt;/a&gt;是开源的差异比较工具，只运行于Windows平台。&lt;/p&gt;
&lt;p&gt;具有以下实用特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持文件内容和文件、文件夹差异比较&lt;/li&gt;
&lt;li&gt;文件内容比较采用左右双栏显示，支持语法高亮&lt;/li&gt;
&lt;li&gt;提供Windows资源管理器右键菜单，以选择文件或文件夹进行比较&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;具有以下不足：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;文件夹比较结果以单栏显示，不直观&lt;/li&gt;
&lt;li&gt;仅支持两方比较，不支持多方比较&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用时的注意事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用树状的列表显示文件夹比较结果可以稍微缓解单栏显示导致的不直观的问题&lt;/li&gt;
&lt;li&gt;Windows资源管理器的右键菜单需要在设置界面手工设置才能加入选取不同目标进行比较的菜单项&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;相较于商业的Beyong Compare等工具，WinMerge在操作的直观度和功能细节上存在不足，但是在差异比较的主要功能上，WinMerge完全可以胜任日常工作。同时，由于免费，WinMerge可以作为这些商业软件很好的替代工具。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;后记：这些天越来越对使用未授权的商业软件感到不安，于是开始寻找这些工具的开源、免费替代品。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>升级fcitx到4.0</title><link>http://0x3f.org/posts/upgraded-to-fcitx4/</link><pubDate>Sat, 20 Nov 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/upgraded-to-fcitx4/</guid><description>&lt;p&gt;虽然是个大版本，但4.0在实际功能上并没有太大的进步。新版本相对于3.x增加的主要特性是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持皮肤&lt;/li&gt;
&lt;li&gt;图形界面的配置工具&lt;/li&gt;
&lt;li&gt;增加系统托盘图标&lt;/li&gt;
&lt;li&gt;托盘图标和输入条提供右键菜单，如皮肤切换、选择输入法等&lt;/li&gt;
&lt;li&gt;放弃GBK编码，改用UTF-8编码&lt;/li&gt;
&lt;li&gt;拼音支持多词库&lt;/li&gt;
&lt;li&gt;一系列细节功能及Bug修复&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最主要的特性只有前两个，可见fcitx 4.0只是这个项目涅槃后的一个新的起点，象征意义大于实际意义，尤其对于码表输入法用户来说是这样。三年前我就&lt;a href="http://0x3f.org/?p=185"&gt;说过&lt;/a&gt;，fcitx在用户造词上有个致命缺陷，就是对于多音字它总是使用字母表中声母靠前的编码，对于音码或者音形码输入法来说，这样造出来的词的编码经常会是错的，更糟糕的是用户还不容易自行修改词组编码。三年后的今天，新版本并没有解决这个问题。&lt;/p&gt;
&lt;p&gt;此外，需要注意的是，新版本对界面和易用性的改进也带来一些负面的影响，fcitx不再是当年以轻巧著称的那只小企鹅了，在我这里，它的内存占用达到了26M，所幸反应速度仍然很快。&lt;/p&gt;
&lt;p&gt;三年前，由于众所周知的原因，fcitx的路线图显得非常混乱，几个新版本都非常不稳定，所以我不再使用源中的版本，转而编译安装了新版本中相对稳定的黑色星期五版，不知不觉中三年过去了，想到一直用著这个版本就这么过来了，很感慨。要卸载编译安装的程序就得用源码重新configure一下再make uninstall，所幸还能在&lt;a href="http://www.fcitx.org/download/fcitx-3.5-BlackFri.tar.bz2"&gt;这里&lt;/a&gt;找到这个版本。&lt;/p&gt;
&lt;p&gt;Archlinux下安装AUR中的fcitx-config时报如下错误：&lt;/p&gt;
&lt;blockquote&gt;
ERROR: certificate common name “*.github.com” doesn’t match requested host name “github.com”.
&lt;/blockquote&gt;
&lt;p&gt;需要修改/etc/makepkg.conf，使wget在下载源码时不做安全验证：&lt;/p&gt;
&lt;blockquote&gt;
# 增加--no-check-certificate参数
DLAGENTS=('ftp::/usr/bin/wget -c --passive-ftp -t 3 --waitretry=3'
'http::/usr/bin/wget -c -t 3 --waitretry=3 --no-check-certificate'
'https::/usr/bin/wget -c -t 3 --waitretry=3 --no-check-certificate'
'rsync::/usr/bin/rsync -z'
'scp::/usr/bin/scp -C')
&lt;/blockquote&gt;
&lt;p&gt;新版本的稳定性不如黑色星期五版，如果把简繁转换热键修改为ALT+J，使用时会导致fcitx崩溃。加之实际功能的改进不大，所以是否升级就无可无不可了。&lt;/p&gt;</description></item><item><title>调整Arch的磁盘分区</title><link>http://0x3f.org/posts/adjust-disk-partitions-in-archlinux/</link><pubDate>Sat, 13 Nov 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/adjust-disk-partitions-in-archlinux/</guid><description>&lt;p&gt;&lt;h2&gt;简述&lt;/h2&gt;&lt;/p&gt;
&lt;p&gt;目标：移除Windows 7，整块硬盘完全分配给Archlinux。&lt;/p&gt;
&lt;p&gt;原分区结构：&lt;/p&gt;
&lt;p&gt;
&lt;table class="art_tbl"&gt;
&lt;tr&gt;&lt;th class="art_tbl_th"&gt;分区&lt;/th&gt;&lt;th class="art_tbl_th"&gt;类型&lt;/th&gt;&lt;th class="art_tbl_th"&gt;挂载&lt;/th&gt;&lt;th class="art_tbl_th"&gt;文件系统&lt;/th&gt;&lt;th class="art_tbl_th"&gt;容量&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda1&lt;/td&gt;&lt;td class="art_tbl_td"&gt;主分区，启动分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;Windows 7的安装分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;ntfs&lt;/td&gt;&lt;td class="art_tbl_td"&gt;30G&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda2&lt;/td&gt;&lt;td class="art_tbl_td"&gt;扩展分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;-&lt;/td&gt;&lt;td class="art_tbl_td"&gt;-&lt;/td&gt;&lt;td class="art_tbl_td"&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda5&lt;/td&gt;&lt;td class="art_tbl_td"&gt;逻辑分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;Windows的D盘&lt;/td&gt;&lt;td class="art_tbl_td"&gt;ntfs&lt;/td&gt;&lt;td class="art_tbl_td"&gt;40G&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda3&lt;/td&gt;&lt;td class="art_tbl_td"&gt;主分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;/&lt;/td&gt;&lt;td class="art_tbl_td"&gt;ext3&lt;/td&gt;&lt;td class="art_tbl_td"&gt;78G&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda4&lt;/td&gt;&lt;td class="art_tbl_td"&gt;交换分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;swap&lt;/td&gt;&lt;td class="art_tbl_td"&gt;-&lt;/td&gt;&lt;td class="art_tbl_td"&gt;2G&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;调整后分区结构：&lt;/p&gt;
&lt;p&gt;
&lt;table class="art_tbl"&gt;
&lt;tr&gt;&lt;th class="art_tbl_th"&gt;分区&lt;/th&gt;&lt;th class="art_tbl_th"&gt;类型&lt;/th&gt;&lt;th class="art_tbl_th"&gt;挂载&lt;/th&gt;&lt;th class="art_tbl_th"&gt;文件系统&lt;/th&gt;&lt;th class="art_tbl_th"&gt;容量&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda1&lt;/td&gt;&lt;td class="art_tbl_td"&gt;主分区，启动分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;/&lt;/td&gt;&lt;td class="art_tbl_td"&gt;ext3&lt;/td&gt;&lt;td class="art_tbl_td"&gt;30G&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda2&lt;/td&gt;&lt;td class="art_tbl_td"&gt;主分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;/home&lt;/td&gt;&lt;td class="art_tbl_td"&gt;ext3&lt;/td&gt;&lt;td class="art_tbl_td"&gt;120G&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="art_tbl_td"&gt;/dev/sda3&lt;/td&gt;&lt;td class="art_tbl_td"&gt;交换分区&lt;/td&gt;&lt;td class="art_tbl_td"&gt;swap&lt;/td&gt;&lt;td class="art_tbl_td"&gt;-&lt;/td&gt;&lt;td class="art_tbl_td"&gt;2G&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;&lt;h2&gt;步骤&lt;/h2&gt;&lt;/p&gt;
&lt;ol&gt;
```bash
sudo grub-install /dev/sda
```
```bash
sudo vi /boot/grub/menu.lst
```
# (2) Arch Linux
title Arch Linux
root (hd0,0)
kernel /boot/vmlinuz26 root=/dev/sda1 resume=/dev/sda4 ro acpi_osi="Linux"
initrd /boot/kernel26.img
&lt;/blockquote&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/?p=1699"&gt;安装U盘启动的Puppy Linux&lt;/a&gt;&lt;/li&gt;
```bash
mkfs.ext3 /dev/sda1
```
```bash
# 先点击桌面上sda1和sda3的盘符，使之被挂载到/mnt下
cd /mnt/sda3
cp -a * /mnt/sda1
```
```bash
vi /mnt/sda1/etc/fstab
```
# 修改必要的挂载点，如将根目录的挂载点由sda3改为sda1：
/dev/sda1 / ext3 defaults,noatime 0 1
&lt;/blockquote&gt;&lt;/li&gt;
&lt;li&gt;重启系统，并引导到新分区上的系统中&lt;/li&gt;
```bash
sudo grub-install /dev/sda
```
&lt;li&gt;重启并进入Puppy，使用gparted删除除sda1以外的所有分区，然后在空闲的空间上创建ext3格式的主分区sda2和交换分区sda3&lt;/li&gt;
```bash
cp -a /mnt/sda1/home/* /mnt/sda2
rm -rf /mnt/sda1/home/*
```
```bash
vi /mnt/sda1/etc/fstab
```
# 将fstab中磁盘分区的挂载点配置为如下内容
/dev/sda1 / ext3 defaults,noatime 0 1
/dev/sda2 /home ext3 defaults,noatime 1 2
/dev/sda3 swap swap defaults 0 0
```bash
vi /mnt/boot/grub/menu.lst
```
# 将原来启动项中的sda3修改为sda1，由于配置过休眠，也将resume参数中的sda4改为sda3，即交换分区
&lt;/blockquote&gt;
&lt;li&gt;重启系统&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;h2&gt;后记&lt;/h2&gt;&lt;/p&gt;</description></item><item><title>制作Puppy Linux的启动U盘</title><link>http://0x3f.org/posts/howto-create-bootable-udisk-for-puppylinux/</link><pubDate>Thu, 11 Nov 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-create-bootable-udisk-for-puppylinux/</guid><description>&lt;p&gt;Puppy Linux的体积只有一百多兆字节，但图形界面实现得很完备，也包含了很多短小精悍的工具，安装和使用都很方便，非常适合用来做日常维护工具盘。&lt;/p&gt;
&lt;p&gt;Puppy自带了傻瓜式的启动U盘制作工具，但官方只提供整个发行版的ISO镜像下载，通常需要刻录成光盘并引导系统启动后才可以继续将Puppy安装到U盘。其实也可以不刻录光盘，而是把Puppy安装到硬盘上。&lt;/p&gt;
&lt;p&gt;Puppy本身封装得很好，对软硬件环境的要求不高，完全可以安装到一个独立的目录中而不影响其它操作系统。本文基于Linux环境下通过GRUB引导的前提，Windows下应该可以通过GRUB4DOS引导。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;挂载Puppy的ISO镜像到一个目录：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mount -o loop puppy.iso /media/puppy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;复制镜像中的所有文件到根目录下的puppy目录：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir /puppy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp -a /media/puppy/* /puppy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="3"&gt;
&lt;li&gt;修改GRUB的引导文件，加入Puppy的引导项：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo vi /boot/grub/menu.lst
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;blockquote&gt;
# (2) Puppy
title Puppy
root (hd0,2)
kernel /puppy/vmlinuz root=/dev/ram0
initrd /puppy/initrd.gz
&lt;/blockquote&gt;
&lt;ol start="4"&gt;
&lt;li&gt;
&lt;p&gt;重启系统并启动到Puppy&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用桌面上的&lt;strong&gt;Setup&lt;/strong&gt;中的&lt;strong&gt;Puppy Universal Installer&lt;/strong&gt;制作启动U盘。不过虽然这是官方推荐的制作工具，但我的杂牌U盘无论如何也不能引导系统，最后使用另一个备选的工具“&lt;strong&gt;BootFlash USB Installer&lt;/strong&gt;”的&lt;strong&gt;USB-HDD&lt;/strong&gt;模式制作成功。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>搭建自己的Twitter API</title><link>http://0x3f.org/posts/howto-setup-twitter-api-of-your-own/</link><pubDate>Fri, 01 Oct 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-setup-twitter-api-of-your-own/</guid><description>&lt;h2&gt; 创建Twitter应用程序 &lt;/h2&gt;
&lt;p&gt;从2010年9月起，twitter只支持第三方应用程序使用oauth方式登录。要使用第三方API程序，就必须先在twitter中创建应用程序。&lt;/p&gt;
&lt;p&gt;申请地址如下：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/apps/"&gt;https://twitter.com/apps/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;填写信息时，&lt;b&gt;Application Type&lt;/b&gt;应该选&lt;b&gt;Browser&lt;/b&gt;，&lt;b&gt;Default Access type&lt;/b&gt;应选&lt;b&gt;Read &amp;amp; Write&lt;/b&gt;，&lt;b&gt;User Twitter for login&lt;/b&gt;不选，其它随便。&lt;/p&gt;
&lt;p&gt;创建成功后，该应用程序的&lt;b&gt;Consumer key&lt;/b&gt;和&lt;b&gt;Consumer secret&lt;/b&gt;在部署API时一般都要用到。&lt;/p&gt;
&lt;h2&gt; 第三方API程序 &lt;/h2&gt;
&lt;h3&gt; gtap &lt;/h3&gt;
&lt;p&gt;&lt;a href="http://code.google.com/p/gtap/"&gt;gtap&lt;/a&gt;使用python开发，可部署在appspot上。&lt;/p&gt;
&lt;p&gt;部署前，先修改&lt;b&gt;app.yaml&lt;/b&gt;，填写在appspot上创建的应用程序的ID，并使用符号#注释掉&lt;b&gt;secure: always&lt;/b&gt;，因为GFW屏蔽了appspot的https。&lt;/p&gt;
&lt;p&gt;然后修改&lt;b&gt;main.py&lt;/b&gt;，填写Consumer key和Consumer secret。&lt;/p&gt;
&lt;p&gt;最后安装&lt;a href="http://code.google.com/intl/zh-CN/appengine/downloads.html"&gt;App Engine SDK&lt;/a&gt;，使用其中的&lt;b&gt;appcfg.py&lt;/b&gt;上传gtap文件夹：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;appcfg.py update gtap
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在浏览器中（此时应使用可以翻墙的代理）访问在appspot上创建的应用程序的URL地址（如：http://xxx.appspot.com ），在打开的页面中点击&lt;b&gt;Sign in with Twitter&lt;/b&gt;，然后在跳转到的页面中点击&lt;b&gt;Allow&lt;/b&gt;按钮。在跳转到的页面上修改API的密码（据说有些客户端要求API的密码与Twitter的密码一致）。&lt;/p&gt;
&lt;p&gt;在客户端中使用API的地址如下：&lt;/p&gt;
&lt;blockquote&gt;
http://xxx.appspot.com/
&lt;/blockquote&gt;
&lt;p&gt;其中，&lt;b&gt;xxx&lt;/b&gt;是appspot应用程序的ID，末尾的斜杠必不可少。&lt;/p&gt;
&lt;h3&gt; twip &lt;/h3&gt;
&lt;p&gt;&lt;a href="http://code.google.com/p/twip/"&gt;twip&lt;/a&gt;使用php开发，应部署在支持PHP的服务器上。&lt;/p&gt;
&lt;p&gt;首先将&lt;b&gt;config-example.php&lt;/b&gt;改名为&lt;b&gt;config.php&lt;/b&gt;，然后修改其中的OAUTH_KEY/OAUTH_SECRET/BASE_URL三项内容，前两项分别是Consumer key和Consumer secret，base_url应该是twip部署到服务器上后的URL地址（如http://myblog.com/twip/ ，最后的斜杠必不可少）。&lt;/p&gt;
&lt;p&gt;然后在浏览器中访问上面的base_url，选择使用o模式，API地址会在最后的页面中输出。&lt;/p&gt;
&lt;h2&gt; 补充说明 &lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;当前版本的Google App Engine SDK要求使用python 2.5，但如果只是用来上传应用程序到appspot，2.5以上版本的python也可以用，只是在上传时会报某些模块已不推荐使用。如果使用appcfg.py时报找不到2.5版本的python，可以强制使用已安装的新版本的python执行之，即：python appcfg.py update gtap&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>目录与文件的存储空间占用分析工具</title><link>http://0x3f.org/posts/storage-space-analysing-tools/</link><pubDate>Fri, 01 Oct 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/storage-space-analysing-tools/</guid><description>&lt;h3&gt;du&lt;/h3&gt;
&lt;p&gt;du是命令行中用于查看目录和文件的空间占用情况的指令。&lt;/p&gt;
&lt;p&gt;常用示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;du -h /tmp/logs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3&gt;ncdu&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://dev.yorhel.nl/ncdu"&gt;ncdu&lt;/a&gt;为du提供了一个基于NCurses的命令行用户界面，并能够按照多种条件对分析结果进行排序，它大大简化了du指令的使用。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/xQINh1zrBdZcY27Evm9Cog?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/TKWkJk8hkjI/AAAAAAAABfU/vTIJqHTxAX0/s400/disk_usage_analyzers-ncdu_01.png" height="250" width="400" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;baobab&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://www.marzocca.net/linux/baobab/index.html"&gt;baobab&lt;/a&gt;使用基于GTK的图形用户界面，突出特点是可以分析远程目录。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/rGbtFe2Je23r1TB1MmX-tA?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TKWkJ1_yLJI/AAAAAAAABfY/pt_peEEU2f8/s400/disk_usage_analyzers-baobab_01.png" height="400" width="386" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;参考&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://www.vpser.net/manage/ncdu.html"&gt;磁盘目录占用空间计算排序工具 - ncdu&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>中秋后记</title><link>http://0x3f.org/posts/note-after-the-mid-autumn-day/</link><pubDate>Sun, 26 Sep 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/note-after-the-mid-autumn-day/</guid><description>&lt;p&gt;可以让回忆放肆一些。&lt;/p&gt;
&lt;p&gt;中秋的晚上公司餐厅放电影，《邻家特工》和《越光宝盒》，本来打算看完《越光》就走，结果先放的是《特工》。也好，复习一下，好在这片子不错，再看也挺有意思。《越光》纯属烂片，但是如今看看这种不费脑子的东西也变得无可无不可。免费的零食很烘托气氛，唯一的惊喜是居然还有罐装啤酒。&lt;/p&gt;
&lt;p&gt;回到住处的当夜就发布了Dumperor。其实这个东西很早就开始做了，起初的目的是为了判断数据库脚本从SQL Server迁移到Oracle和MySQL是否成功。单纯的迁移只能保证修改后的脚本在这两个数据库中执行不会报错，但究竟是不是该执行的东西都成功执行了，一般很难判断，尤其是那帮家伙总是在发版前一两天才告诉我要迁移脚本，那么多不规范的语句，能保证不报错就已经不错了，遑论没有遗漏。所以就著手做一个数据库表结构和数据的导出工具，这样只需用diff工具比较标准数据库和测试数据库导出的脚本就可以了。&lt;/p&gt;
&lt;p&gt;从一开始我就决定不使用公司产品的一行代码。其实做这个东西最大的麻烦不是来自来自于如何查询不同的数据库的表结构，而是数据库抽象层。如果要白手起家搞个抽象层的话，我想可能代码量比Dumperor本身都大，于是选择了Yii框架。后来在Dumperor基本成型时又觉得为了仅仅使用最基本的数据库查询功能就捆绑这么大一个框架，有点搞笑，谢天谢地，我终于花时间学了PDO。&lt;/p&gt;
&lt;p&gt;中秋节放假的第二天，开始读Google Code上关于Chrome扩展开发的官方文档。这事源于本尊被另一个Chrome扩展作者无视了。&lt;/p&gt;
&lt;p&gt;一直强迫自己喜欢上Firefox，但都败了。本来对Opera充满希望，但是从10.0起它带给我的除了失望就是更多的失望，这个东西的发展就像它的国家的位置一样怪异，你永远不能以常人的思维去臆测Opera的开发者，他们就像一群母系氏族社会的娘们儿一样整天跟著感觉走。&lt;/p&gt;
&lt;p&gt;于是不知道什么时候我就开始经常用Chrome了，前段时间开始用一个扩展辅助MLDonkey下载。这个东西会在工具栏里添加一个图标，唯一的作用就是打开选项设置页面设置那个也许这辈子都只需要设置一次的MLDonkey的URL地址。于是我给那个扩展的作者写了封邮件，那家伙居然到现在都没有回复。&lt;/p&gt;
&lt;p&gt;所以本尊决定无视他了。太祖武皇帝的那句丰衣足食的圣谕真是至理名言，读完文档我就发现这个扩展完全应该用Chrome的Page Action取代Browser Action，简单地说就是当且仅当本页面中包含有可下载的资源时才在地址栏中显示一个图标，而不应该总是在工具栏占用一个图标的位置。&lt;/p&gt;
&lt;p&gt;随后要做的就是用AJAX请求取代弹出新窗口的方式添加下载任务，我嫌每次添加一个下载任务后都要关闭一个弹出窗口太麻烦。我的目标是用AJAX请求将要下载的任务在后台传递给MLDonkey，并用Chrome的Desktop Notification功能弹出桌面提示对话框显示结果状态。这样很优雅。&lt;/p&gt;
&lt;p&gt;但是实际去做的时候问题来了，虽然Chrome本身允许扩展使用跨域的AJAX，但是至少在和MLDonkey进行通讯时，无论成功与否，得到的返回信息都是空的，状态码也都是0。这个问题浪费了我几乎一整天的时间，最终我决定用AJAX的请求响应时间来判断失败或成功，因为一次AJAX请求响应过程在MLDonkey没启动的时候耗费的时间一般会比正在运行时要长。这就要求每个用户都要根据自己的情况设定合适的超时时间。为了避免麻烦，最后还是实现了通过弹窗添加下载任务的模式，毕竟这个东西总是可靠的。&lt;/p&gt;
&lt;p&gt;要发布的时候发现如今在Chrome Extension Gallery中发布扩展居然要收费了，虽然只是一次性的。最后花了八两银子注册了Google Checkout账户，又付了五刀美帝币，才把DonkeyBuddy传上去。发布个免费扩展还得倒贴，本尊也太背了吧。&lt;/p&gt;
&lt;p&gt;节后收到了Dell sk8115键盘、HP百灵无线鼠标和Nokia BH-105蓝牙耳机，sk8115是用来让我的纤纤玉手撒野的，百灵鼠是用来接替即将退役的雷柏7100的，而BH-105和我的小七搭配得天衣无缝。&lt;/p&gt;
&lt;p&gt;很久没有安静地整理一下头绪了，感谢我那价值四十两银子的Dell sk8115，它让我显得如此的语无伦次。&lt;/p&gt;</description></item><item><title>DonkeyBuddy: A Chrome Extension for MLDonkey</title><link>http://0x3f.org/posts/donkeybuddy-a-chrome-extension-for-mldonkey/</link><pubDate>Fri, 24 Sep 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/donkeybuddy-a-chrome-extension-for-mldonkey/</guid><description>&lt;div class="illustration_left"&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/CLpE8Gtpb3r3F9kcqmS60g?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/TJyWhIpMAgI/AAAAAAAABec/KDw6n_qdQ98/s800/donkey-256x256.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;DonkeyBuddy&lt;/strong&gt; is an extension for Google Chrome Browser. It's intended to make life easier when you add downloading tasks to MLDonkey.&lt;/p&gt;
&lt;h2&gt;Features&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Users can choose how to interact with MLDonkey, either by AJAX or
popup windows.&lt;/li&gt;
&lt;li&gt;The AJAX mode interacts with MLDonkey by AJAX requests and uses
desktop notifications to show the results, so it won't bother you by
popping up windows and forcing you to close them.&lt;/li&gt;
&lt;li&gt;The popup-window mode interacts with MLDonkey by popping up a window
and displays results in it, this is always a reliable way to add
downloads but annoying.&lt;/li&gt;
&lt;li&gt;An icon will be displayed in the location bar only when downloadable
resources are found in the current tab, so it saves you the space in
both toolbar and location bar.&lt;/li&gt;
&lt;li&gt;Batch downloading.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Screenshots&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Location bar icon: &lt;br /&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/021647BS--VLalgORMtuVA?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/TJyWhUJIzBI/AAAAAAAABeg/ZQ2WeLfTf0k/s800/donkeybuddy-location_bar_icon_01.png" alt="image" /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Desktop notification: &lt;br /&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/aBu0jSZu3y7Ux-EKKgQibQ?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/TJyWhchc1lI/AAAAAAAABek/O3OuDRkgL88/s400/donkeybuddy-notification_01.png" alt="image" /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Popup window: &lt;br /&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/GbGe38VG8mU_LyXZDFYgtA?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/TJyWhmg-04I/AAAAAAAABeo/8cbj0a-m_Fg/s400/donkeybuddy-popup_window_01.png" alt="image" /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Settings page: &lt;br /&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/uUKzfwcmEQfJaHY6cHVNqw?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TJyWhsEQILI/AAAAAAAABes/ezlPD6jaUuQ/s400/donkeybuddy-settings_01.png" alt="image" /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Install&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/hbajjpcakkngealbehjippmdbfapodnn"&gt;https://chrome.google.com/webstore/detail/hbajjpcakkngealbehjippmdbfapodnn&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Dumperor: Multi-Database Dumping Toolkit</title><link>http://0x3f.org/posts/dumperor-as-a-multidb-dumping-tool/</link><pubDate>Thu, 23 Sep 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/dumperor-as-a-multidb-dumping-tool/</guid><description>&lt;div class="illustration_left"&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/lR2jgtHibgYwfhCy3fJyMQ?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TI44ZufyOhI/AAAAAAAABeM/6ElHu0gdYzY/s800/dumperor.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Dumperor&lt;/strong&gt; is a multi-database dumping toolkit. It dumps table structures and data from databases, and generates CREATE-TABLE SQL statements for table structures or INSERT SQL statements for data.&lt;/p&gt;
&lt;p&gt;Part of the original intention for developing Dumperor is to check whether a migration of SQL scripts from one database to another is successful, you know, by comparing the differences between two files, one dumped before executing scripts and the other after. The second part is to ensure that upgrades to table structures or data not miss anything, similarly. The last part is to take samples of databases and put up development or testing environments with them, or even replace sensitive information with fake data.&lt;/p&gt;</description></item><item><title>Arch不完全降温笔记</title><link>http://0x3f.org/posts/howto-cool-archlinux-down/</link><pubDate>Sat, 18 Sep 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-cool-archlinux-down/</guid><description>&lt;p&gt;主要目标是解决我的X200在Archlinux&lt;em&gt;（本文内容均基于此发行版）&lt;/em&gt;下CPU温度长期居高不下的问题，基本原理是使用&lt;a href="http://wiki.archlinux.org/index.php/Cpufrequtils"&gt;cpufrequtils&lt;/a&gt;根据CPU负载状况自动变频，和使用&lt;a href="http://wiki.archlinux.org/index.php/Laptop_Mode_Tools"&gt;laptop-mode-tools&lt;/a&gt;实现其它硬件设备的自动节能。最直接的效果是省电，从而延长电池的使用时间，产生的附加影响就是CPU及笔记本整体的温度下降。我几乎不用电池，所以节能不是我的关注点，但降温却是我所欲也。&lt;/p&gt;
&lt;p&gt;首先安装cpufrequtils，并将&lt;strong&gt;acpi-cpufreq&lt;/strong&gt;、&lt;strong&gt;cpufreq_ondemand&lt;/strong&gt;、&lt;strong&gt;cpufreq_powersave&lt;/strong&gt;加入&lt;strong&gt;rc.conf&lt;/strong&gt;的&lt;strong&gt;MODULES&lt;/strong&gt;中，使系统在启动时加载这些模块。&lt;/p&gt;
&lt;p&gt;默认情况下，内核采用cpufreq的performance模式，以获得最高性能，现在用ondemand模式使CPU根据负载状况自动变频。修改&lt;strong&gt;/etc/conf.d/cpufreq&lt;/strong&gt;文件，将&lt;strong&gt;governor&lt;/strong&gt;项设为&lt;strong&gt;ondemand&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;将&lt;strong&gt;cpufreq&lt;/strong&gt;加入&lt;strong&gt;rc.conf&lt;/strong&gt;的&lt;strong&gt;DAEMONS&lt;/strong&gt;中，此守护进程会在系统启动时读取配置文件&lt;strong&gt;/etc/conf.d/cpufreq&lt;/strong&gt;中的设置项，故上面设置的ondemand模式会在系统启动时得以自动生效。&lt;/p&gt;
&lt;p&gt;然后安装laptop-mode-tools，并修改&lt;strong&gt;/etc/laptop-mode/laptop-mode.conf&lt;/strong&gt;，打开所有的三个以&lt;strong&gt;ENABLE&lt;/strong&gt;开头的选项，和所有以&lt;strong&gt;CONTROL&lt;/strong&gt;开头的选项。&lt;/p&gt;
&lt;p&gt;将&lt;strong&gt;laptop-mode&lt;/strong&gt;加入&lt;strong&gt;rc.conf&lt;/strong&gt;的&lt;strong&gt;DAEMONS&lt;/strong&gt;中，使其随系统自动启动。&lt;/p&gt;
&lt;p&gt;修改&lt;strong&gt;/etc/laptop-mode/conf.d/usb-autosuspend.conf&lt;/strong&gt;，此配置文件用来配置laptop-mode如何管理USB设备的电源使用。我希望在任何时候都启用USB设备自动节能，但需要把我的无线鼠标排除在外，故作如下配置：&lt;/p&gt;
```bash
# 启用USB设备自动挂起
CONTROL_USB_AUTOSUSPEND="auto"
# 将不使用自动挂起的USB设备的ID填在下面，使用lsusb命令查看ID
AUTOSUSPEND_USBID_BLACKLIST="04fc:05dc"
# 总是启用USB自动挂起
BATT_SUSPEND_USB=1
LM_AC_SUSPEND_USB=1
NOLM_AC_SUSPEND_USB=1
```
&lt;p&gt;类似地，修改&lt;strong&gt;intel-hda-powersave.conf&lt;/strong&gt;，此配置文件用于配置laptop-mode如何管理Intel HDA音频芯片的电源使用。我希望一直启用声卡自动节能，并适当地将自动进入节电模式的空闲时间增加到30秒，故配置如下：&lt;/p&gt;
```bash
# 启用Intel音频芯片电源管理
CONTROL_INTEL_HDA_POWER="auto"
# 总是启用
BATT_INTEL_HDA_POWERSAVE=1
LM_AC_INTEL_HDA_POWERSAVE=1
NOLM_AC_INTEL_HDA_POWERSAVE=1
# 适当地设置声卡进入节电模式的超时时间
INTEL_HDA_DEVICE_TIMEOUT=30
```
&lt;p&gt;类似地，修改&lt;strong&gt;intel-sata-powermgmt.conf&lt;/strong&gt;，启用sata硬盘接口的电源管理。由于我用Blueman控制蓝牙设备，一般不用时都将其关闭，同时经常使用wifi，故蓝牙和无线网卡均未作配置。&lt;/p&gt;
&lt;p&gt;最后，关闭conky,Firefox和Chromium，&lt;a href="http://www.lesswatts.org/projects/powertop/"&gt;powertop&lt;/a&gt;显示conky是个很吵闹的东西，关掉它可以使&lt;strong&gt;Wakeups-from-idle per second&lt;/strong&gt;的值下降很多，另外Chromium和Firefox也是耗电大户。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在此之前，系统空闲时CPU温度一般是50多度，普通使用时一般在60多度，如果开了kvm虚拟机会达到60至90度间。经过以上设置，系统空闲时CPU温度一度下降到39度，即使开了虚拟机，一般也可维持在50到80度间。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;另外，对于以上内容，我还有些没搞明白的地方和要补充说明的东西：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;虽然将laptop-mode加入rc.conf且已随系统启动，但使用命令“&lt;strong&gt;cat /proc/sys/vm/laptop_mode&lt;/strong&gt;”查询得到的结果仍然是0，也就是说没有自动启用laptop-mode，必须使用命令“&lt;strong&gt;sudo /etc/rc.d/laptop-mode restart&lt;/strong&gt;”手动重启才行。目前没有找到解决办法。&lt;/li&gt;
&lt;li&gt;虽然启用laptop-mode接管声卡电源管理，但没找到查看是否生效的方法，于是在/etc/rc.local中加入命令“&lt;strong&gt;echo 1 &amp;gt; /sys/module/snd&lt;em&gt;hda&lt;/em&gt;intel/parameters/power_save&lt;/strong&gt;”以强制声卡节电。&lt;/li&gt;
&lt;li&gt;Intel的powertop是个好东西，用它可以查看哪些进程最影响CPU节能。我们优化的标准之一就是使powertop中显示的“Wakeups-from-idle per second”尽可能地减少。powertop的另一个特点就是通过自动检查当前系统中电源使用的配置情况给出优化的建议，这是个很贴心的功能。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;鉴于目前存疑较多并将继续尝试，所以在标题中特别注明“不完全”三个字……&lt;/p&gt;
&lt;h3&gt;参考&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;http://itgen.blogspot.com/2009/03/energy-management-in-linux.html&lt;/li&gt;
&lt;li&gt;http://www.ibm.com/developerworks/cn/linux/l-cpufreq-1/index.html&lt;/li&gt;
&lt;li&gt;http://www.lesswatts.org/&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>使用热键切换Vim的QuickFix窗口打开状态</title><link>http://0x3f.org/posts/howto-toggle-quickfix-in-vim-using-hotkeys/</link><pubDate>Fri, 10 Sep 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-toggle-quickfix-in-vim-using-hotkeys/</guid><description>&lt;p&gt;QuickFix窗口只有打开和关闭的命令，而使用一个热键来切换打开状态可以减少热键资源的浪费，使用也更方便。&lt;/p&gt;
&lt;p&gt;从&lt;a href="http://vim.wikia.com/wiki/Toggle_to_open_or_close_the_quickfix_window"&gt;这里&lt;/a&gt;找到使用自定义函数完成此功能的方法：使用一个全局变量记录QuickFix窗口的打开状态，从而判断是应该关闭还是打开。但其提供的函数存在状态同步的问题，假如在QuickFix窗口中使用“:q”退出窗口，此方法将不能正常工作。评论中给出了很好的解决方法，但其提供的代码有些小问题，修改之后如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;co&lt;/span&gt; :&lt;span class="nx"&gt;QFix&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;nmap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;ct&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;QFixToggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bang&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;nargs&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;? &lt;span class="nx"&gt;QFix&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;QFixToggle&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;bang&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;QFixToggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;forced&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;g:qfix_win&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="nx"&gt;a&lt;/span&gt;:&lt;span class="nx"&gt;forced&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;cclose&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;g:my_quickfix_win_height&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;execute&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;copen &amp;#34;&lt;/span&gt;.&lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;my_quickfix_win_height&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;copen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;augroup&lt;/span&gt; &lt;span class="nx"&gt;QFixToggle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;autocmd&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;BufWinEnter&lt;/span&gt; &lt;span class="nx"&gt;quickfix&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;qfix_win&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;$&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;autocmd&lt;/span&gt; &lt;span class="nx"&gt;BufWinLeave&lt;/span&gt; * &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;g:qfix_win&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;abuf&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;qfix_win&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;unlet&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;:&lt;span class="nx"&gt;qfix_win&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;augroup&lt;/span&gt; &lt;span class="nx"&gt;END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>WordPress Plugin: Batch Cat</title><link>http://0x3f.org/posts/wp-batchcat/</link><pubDate>Sat, 04 Sep 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/wp-batchcat/</guid><description>&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/bqYPszwt0P7OI9snKxv3WA?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TIIMnE-09dI/AAAAAAAABdk/q_hDtyXJozo/s800/wp-batch-cat.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Batch Cat is intended to help users change categories of posts in bulk.&lt;/p&gt;
&lt;p&gt;The main features are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Assign the selected categories to posts.&lt;/li&gt;
&lt;li&gt;Append the selected categories to posts.&lt;/li&gt;
&lt;li&gt;Delete the selected categories from posts.&lt;/li&gt;
&lt;li&gt;Intuitionistic operating manners which come up with people's common practice.&lt;/li&gt;
&lt;li&gt;Configurable number of posts listed in one page.&lt;/li&gt;
&lt;li&gt;Slimming but enough searching and sorting options.&lt;/li&gt;
&lt;li&gt;More in the future.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Screenshot&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/HbcUjNJ5wuK_XtIUxw1GWw?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TIIK1-R9vDI/AAAAAAAABdc/18irrESzXok/s400/wordpress_plugin-batch_cat.png" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>读完《WordPress Plug-in Development》</title><link>http://0x3f.org/posts/after-reading-wordpress-plug-in-development/</link><pubDate>Sun, 29 Aug 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-reading-wordpress-plug-in-development/</guid><description>&lt;p&gt;花了两天时间读完了《WordPress Plug-in Development》，通过实例讲解，很细致，适合用来入门，当然，深度和广度都有限。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/k7nT3M9jrDW1dPv-nzKJvQ?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_ceUJ_lBTHzc/THnN7TJZDlI/AAAAAAAABdI/OBmuprXqpX4/s400/wordpress-plugin-development.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>批量下载视频的BASH脚本</title><link>http://0x3f.org/posts/a-bash-script-downloading-videos-in-batch/</link><pubDate>Sat, 28 Aug 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/a-bash-script-downloading-videos-in-batch/</guid><description>&lt;p&gt;两周前为了批量下载某视频网站中的电视剧，写了个BASH脚本。将电视剧列表页面的URL地址作为唯一参数传给脚本，然后就会把所有视频下载到当前目录下，并自动重命名，同时生成一个M3U格式的播放列表。&lt;/p&gt;
&lt;p&gt;由于在线视频不支持断点续传，所以对于单个视频来说无法实现。但对于整个批量下载任务来说，实现了宏观上的断点续传，已经下载的视频不会被重复下载。由于有些视频网站会在午夜更改视频地址，所以这一点很有用。&lt;/p&gt;
&lt;p&gt;主流视频网站应该是都支持的，我只测试了我下载电视剧的网站，&lt;strong&gt;不支持的都是非主流的！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;唯一可能需要注意的依赖是PHP，必须安装后才能使用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;print_help_msg &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;You see, I&amp;#39;m nothing .&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;check_param &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$#&lt;/span&gt; -ne &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; print_help_msg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;check_m3u &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; ! &lt;span class="o"&gt;[&lt;/span&gt; -a p.m3u &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;wc -l p.m3u&lt;span class="p"&gt;|&lt;/span&gt;awk &lt;span class="s1"&gt;&amp;#39;{ print $1 }&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; -eq &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#EXTM3U&amp;#39;&lt;/span&gt; &amp;gt; p.m3u
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;check_param &lt;span class="nv"&gt;$*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;check_m3u
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;LC_ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;php -r &lt;span class="s2"&gt;&amp;#34;echo urlencode(&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;);&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://www.flvcd.com/parse.php?flag=&amp;amp;format=&amp;amp;kw=&lt;/span&gt;&lt;span class="nv"&gt;$ue&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;sbt=%BF%AA%CA%BCGO%21&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; ! wget &lt;span class="nv"&gt;$parser&lt;/span&gt; -U mozilla -O meta.html &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Unable to touch the parser, check network status for the cause .&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep &lt;span class="s2"&gt;&amp;#34;&amp;lt;N&amp;gt;&amp;#34;&lt;/span&gt; meta.html &amp;gt; title.lst
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep &lt;span class="s2"&gt;&amp;#34;&amp;lt;U&amp;gt;&amp;#34;&lt;/span&gt; meta.html &amp;gt; url.lst
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iconv -f gbk -t utf-8 title.lst -o title.lst
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -i &lt;span class="s1"&gt;&amp;#39;s/&amp;lt;N&amp;gt;//g&amp;#39;&lt;/span&gt; title.lst
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -i &lt;span class="s1"&gt;&amp;#39;s/ //g&amp;#39;&lt;/span&gt; title.lst
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -i &lt;span class="s1"&gt;&amp;#39;s/&amp;lt;U&amp;gt;//g&amp;#39;&lt;/span&gt; url.lst
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;l1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;wc -l title.lst&lt;span class="p"&gt;|&lt;/span&gt;awk &lt;span class="s1"&gt;&amp;#39;{ print $1 }&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;l2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;wc -l url.lst&lt;span class="p"&gt;|&lt;/span&gt;awk &lt;span class="s1"&gt;&amp;#39;{ print $1 }&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$l1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$l2&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Title.lst has &lt;/span&gt;&lt;span class="nv"&gt;$l1&lt;/span&gt;&lt;span class="s2"&gt; lines, but url.lst got &lt;/span&gt;&lt;span class="nv"&gt;$l2&lt;/span&gt;&lt;span class="s2"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$l1&lt;/span&gt; -eq &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Nothing got from the parser, check meta.html for detail info.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;arrTitle&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;cat title.lst&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;arrURL&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;cat url.lst&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;wc -l p.m3u&lt;span class="p"&gt;|&lt;/span&gt;awk &lt;span class="s1"&gt;&amp;#39;{ print $1 }&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$idx&lt;/span&gt; -lt &lt;span class="nv"&gt;$l1&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arrTitle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arrURL&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;idx+1&lt;span class="k"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; ! wget &lt;span class="nv"&gt;$url&lt;/span&gt; -U mozilla -O &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.flv&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Failed fetching &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.flv, maybe its URL has been changed !&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;sed -i &amp;#39;\$a\\&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.flv&amp;#39; p.m3u&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="nv"&gt;$cmd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;done !&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;另外，使用VLC执行播放列表效果灰常不错，视频之间衔接平滑流畅。&lt;/p&gt;</description></item><item><title>启动GVim时自动最大化窗口的方法</title><link>http://0x3f.org/posts/howto-auto-maximize-gvim-at-startup/</link><pubDate>Wed, 25 Aug 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-auto-maximize-gvim-at-startup/</guid><description>&lt;p&gt;根据帮助文档，gvim在windows下的最大化是通过模拟打开窗口菜单并点击最大化菜单项实现的，而在Linux下的方法较为灵活。&lt;/p&gt;
&lt;p&gt;下面的方法是在vim中通过调用wmctrl实现最大化的方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;win32&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;GUIEnter&lt;/span&gt; * &lt;span class="nx"&gt;simalt&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="nx"&gt;GUIEnter&lt;/span&gt; * &lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;MaximizeWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;MaximizeWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;silent&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;wmctrl&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; :&lt;span class="nx"&gt;ACTIVE&lt;/span&gt;: &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;maximized_vert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;maximized_horz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当然也可以通过配置窗口管理器规则实现自动最大化，但上面的方法更灵活。&lt;/p&gt;</description></item><item><title>InstallShield在MySQL和Oracle中执行SQL脚本的方法</title><link>http://0x3f.org/posts/howto-run-sql-scripts-in-mysql-oracle-within-installshield/</link><pubDate>Tue, 24 Aug 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-run-sql-scripts-in-mysql-oracle-within-installshield/</guid><description>&lt;h2&gt;简述&lt;/h2&gt;
&lt;p&gt;InstallShield已经内建了对MySQL和Oracle的支持。但是这个功能是通过ODBC实现的，它对SQL脚本的格式要求非常严格，因此已经通过官方客户端测试的脚本在IS中执行时往往就会报错。&lt;/p&gt;
&lt;p&gt;一般来说，数据库脚本只保证通过官方客户端测试即可，同时维护一份供IS执行的脚本费时费力。因此，考虑安装程序对两数据库的支持通过官方客户端实现。&lt;/p&gt;
&lt;h2&gt;MySQL&lt;/h2&gt;&lt;br&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;function InstallMySQLComponent(szComponent)
NUMBER nResult;
STRING szServer,szDB,szUser,szPassword,sCMD,sOPT,sResult1,sResult2,svLine,sMsg,sPath;
NUMBER nvFileHandle,nvCount;
LIST listStatus;
begin
sMsg = &amp;#39;安装&amp;#39;+szComponent+&amp;#39; ...&amp;#39;;
SdShowMsg(sMsg, TRUE);
// source命令不认识windows路径中的反斜杠，故将SRCDIR中的反斜杠替换成斜杠
sPath = SRCDIR;
StrReplace(sPath, &amp;#39;\\&amp;#39;, &amp;#39;/&amp;#39;, 0);
// Fetch database connection information
SQLRTGetConnectionInfo( &amp;#39;mysql&amp;#39;, szServer, szDB, szUser, szPassword );
sCMD = WINSYSDIR^&amp;#39;cmd.exe&amp;#39;;
sOPT = &amp;#39; /c &amp;#39;+SRCDIR^&amp;#39;mysql.exe -h&amp;#39;+szServer+&amp;#39; -u&amp;#39;+szUser+&amp;#39; -p&amp;#39;+szPassword+&amp;#39; -D&amp;#39;+szDB;
sOPT = sOPT+&amp;#39; -e &amp;#34;source &amp;#39;+sPath^szComponent+&amp;#39;.sql&amp;#34; &amp;gt; &amp;#39;+SRCDIR^&amp;#39;dbstatus.txt 2&amp;gt;&amp;amp;1&amp;#39;;
// Execute the script associated with the given component in database
nResult=LaunchAppAndWait(sCMD, sOPT, WAIT|LAAW_OPTION_HIDDEN);
if (nResult &amp;lt; 0) then
MessageBox(&amp;#39;Failed installing &amp;#39;+szComponent+&amp;#39; !&amp;#39;, SEVERE);
abort;
endif;
// 关闭安装提示
SdShowMsg(&amp;#39;&amp;#39;, FALSE);
// Read dbstatus.txt
OpenFileMode(FILE_MODE_NORMAL);
if (OpenFile(nvFileHandle, SRCDIR, &amp;#39;dbstatus.txt&amp;#39;)&amp;lt;0) then
MessageBox(&amp;#39;Failed checking the status of installing &amp;#39;+szComponent+&amp;#39; !&amp;#39;, SEVERE);
abort;
endif;
listStatus = ListCreate(STRINGLIST);
while GetLine(nvFileHandle, svLine) = 0
ListAddString(listStatus, svLine, AFTER);
endwhile;
CloseFile(nvFileHandle);
// Count how many lines fetched from dbstatus.txt
nvCount = ListCount(listStatus);
if nvCount &amp;gt; 0 then
sMsg = &amp;#34;更新数据库出错，点“是”打开日志文件并退出安装，点“否”直接退出安装。\n&amp;#34;;
sMsg = sMsg+&amp;#34;若错误可忽略，可选择数据库类型“none”以跳过数据库更新并直接更新程序，\n&amp;#34;;
sMsg = sMsg+&amp;#34;然后在数据库中手工执行SQL脚本（安装后保存在script目录下）&amp;#34;;
nResult = AskYesNo(sMsg, YES);
if (nResult = YES) then
LaunchApp(WINSYSDIR^&amp;#39;notepad.exe&amp;#39;, SRCDIR^&amp;#39;dbstatus.txt&amp;#39;);
endif;
abort;
endif;
end;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Oracle&lt;/h2&gt;&lt;br&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;function InstallOracleComponent(szComponent)
NUMBER nResult,nvFileHandle,nIndex,nvCount;
STRING sMsg,szServer,szDB,szUser,szPassword,sCMD,sOPT,sInstance,sTmp,svLine;
LIST listStatus;
begin
sMsg = &amp;#39;安装&amp;#39;+szComponent+&amp;#39; ...&amp;#39;;
SdShowMsg(sMsg, TRUE);
// Fetch database connection information
SQLRTGetConnectionInfo( &amp;#39;oracle&amp;#39;, szServer, szDB, szUser, szPassword );
nIndex = StrFind(szServer, &amp;#39;:&amp;#39;);
nIndex = StrFindEx(szServer, &amp;#39;/&amp;#39;, nIndex);
StrSub(sInstance, szServer, nIndex+1, 100);
sCMD = WINSYSDIR^&amp;#39;cmd.exe&amp;#39;;
sOPT = &amp;#39; /c &amp;#39;+&amp;#39;sqlplus.exe -L -S &amp;#39;+szUser+&amp;#39;/&amp;#39;+szPassword+&amp;#39;@&amp;#39;+sInstance;
sOPT = sOPT+&amp;#39; @&amp;#39;+SRCDIR^szComponent+&amp;#39;.sql &amp;gt; &amp;#39;+SRCDIR^&amp;#39;dbstatus.txt 2&amp;gt;&amp;amp;1&amp;#39;;
// Execute the script associated with the given component in database
nResult=LaunchAppAndWait(sCMD, sOPT, WAIT|LAAW_OPTION_HIDDEN);
if (nResult &amp;lt; 0) then
MessageBox(&amp;#39;Failed installing &amp;#39;+szComponent+&amp;#39; !&amp;#39;, SEVERE);
abort;
endif;
// 关闭安装提示
SdShowMsg(&amp;#39;&amp;#39;, FALSE);
// 在dbstatus.txt中查询字符串holytail，如果存在，说明脚本已执行完
if (FileGrep(SRCDIR^&amp;#39;dbstatus.txt&amp;#39;, &amp;#39;holytail&amp;#39;, svLine, nIndex, RESTART) = 0) then
// 在dbstatus.txt中查询字符串ORA-，如果存在，说明脚本执行出现错误
if (FileGrep(SRCDIR^&amp;#39;dbstatus.txt&amp;#39;, &amp;#39;ORA-&amp;#39;, svLine, nIndex, RESTART) = 0) then
sMsg = &amp;#34;更新数据库出错，点“是”打开日志文件并退出安装，点“否”直接退出安装。\n&amp;#34;;
sMsg = sMsg+&amp;#34;若错误可忽略，可选择数据库类型“none”以跳过数据库更新并直接更新程序，\n&amp;#34;;
sMsg = sMsg+&amp;#34;然后在数据库中手工执行SQL脚本（安装后保存在script目录下）&amp;#34;;
nResult = AskYesNo(sMsg, YES);
if (nResult = YES) then
LaunchApp(WINSYSDIR^&amp;#39;notepad.exe&amp;#39;, SRCDIR^&amp;#39;dbstatus.txt&amp;#39;);
endif;
abort;
endif;
else
sMsg = &amp;#34;更新数据库出错，点“是”打开日志文件并退出安装，点“否”直接退出安装。\n&amp;#34;;
sMsg = sMsg+&amp;#34;若错误可忽略，可选择数据库类型“none”以跳过数据库更新并直接更新程序，\n&amp;#34;;
sMsg = sMsg+&amp;#34;然后在数据库中手工执行SQL脚本（安装后保存在script目录下）&amp;#34;;
nResult = AskYesNo(sMsg, YES);
if (nResult = YES) then
LaunchApp(WINSYSDIR^&amp;#39;notepad.exe&amp;#39;, SRCDIR^&amp;#39;dbstatus.txt&amp;#39;);
endif;
abort;
endif;
end;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;总结&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;为便于获取脚本在数据库中的执行结果，故通过官方客户端执行脚本时通过符号“&lt;strong&gt;&gt;&lt;/strong&gt;”将客户端的输出信息重定向到&lt;strong&gt;dbstatus.txt&lt;/strong&gt;中；同时，使用“&lt;strong&gt;2&gt;&amp;1&lt;/strong&gt;”将标准错误输出重定向到标准输出设备上，当然，会进一步重定向到dbstatus.txt文件中，否则，无法获取出错信息。&lt;/li&gt;
&lt;li&gt;sqlplus执行SQL脚本后不会自动退出，故应在Oracle的脚本后加上语句“&lt;strong&gt;exit;&lt;/strong&gt;”。&lt;/li&gt;
&lt;li&gt;重载&lt;strong&gt;OnSQLComponentInstalled()&lt;/strong&gt;函数，并在其中禁止MySQL和Oracle的SQL脚本对应的Component被执行安装，然后通过以上两个函数更新数据库。&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>使Thinkpad的静音按钮能被识别的方法</title><link>http://0x3f.org/posts/howto-make-thinkpad-mute-button-detected-on-linux/</link><pubDate>Mon, 09 Aug 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-make-thinkpad-mute-button-detected-on-linux/</guid><description>&lt;p&gt;我的型号是X200，问题表现为在GNOME或XFCE下静音按钮无效，使用xev也捕获不到输入信号，而音量增加和减小按钮可以正常使用且有OSD。&lt;/p&gt;
&lt;p&gt;解决办法是在grub的启动菜单中，给内核加上参数&lt;strong&gt;acpi_osi=“Linux”&lt;/strong&gt;，如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# (0) Arch Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;title Arch Linux
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;root &lt;span class="o"&gt;(&lt;/span&gt;hd0,2&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kernel /boot/vmlinuz26 &lt;span class="nv"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sda3 &lt;span class="nv"&gt;resume&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sda4 ro &lt;span class="nv"&gt;acpi_osi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Linux&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;initrd /boot/kernel26.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;从查到的资料看，&lt;strong&gt;acpi_osi&lt;/strong&gt;参数是用来指定操作系统接口的，据说有些硬件都只针对Windows做了测试或优化，对于这些硬件，如果将内核的操作系统接口指定为Linux，则有可能会出问题。所以内核从2.6.23版本开始，此参数的默认值被改成了“&lt;strong&gt;!Linux&lt;/strong&gt;”，以保证更广泛的兼容性和稳定性。&lt;/p&gt;
&lt;p&gt;而根据&lt;a href="http://www.thinkwiki.org/wiki/Mute_button"&gt;这里&lt;/a&gt;的说法，thinkpad一直以来在对Linux的兼容程度上有很好的口碑，故可以放心添加这个参数。&lt;/p&gt;
&lt;p&gt;另外，xfce下使用OSD需要安装xfce4-volumed。&lt;/p&gt;</description></item><item><title>swfdec：简单好用的Flash播放器</title><link>http://0x3f.org/posts/swfdec-as-a-slim-flash-player/</link><pubDate>Sun, 01 Aug 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/swfdec-as-a-slim-flash-player/</guid><description>&lt;p&gt;早在keke童鞋的&lt;a href="http://www.imkeke.net/linux/flash-player-swfdec.html"&gt;博客&lt;/a&gt;上见过，直到今天下载了个flash视频教程要看时才想起来，毕竟已经不是几年前Flash很火的时候了，为了降低CPU占用，我连Chromium的Flash插件都禁用了。&lt;/p&gt;
&lt;p&gt;使用后的感觉就是简单实用，有暂停，有快进，能调进度，功能一样不多，一样不少。&lt;/p&gt;
&lt;p&gt;要装两个包，swfdec是解码包，swfdec-gnome是播放器。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://swfdec.freedesktop.org"&gt;&lt;a href="http://swfdec.freedesktop.org"&gt;http://swfdec.freedesktop.org&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/pBEyuoK_FQwurdii1Oekdg?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/TFWQ5SwzQnI/AAAAAAAABcc/IFg7kX6pXD4/s400/2010-08-01.23%3A17%3A32.%E6%88%AA%E5%8F%96%E9%80%89%E5%8C%BA.01.png" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>TTL线在Linux下的用法</title><link>http://0x3f.org/posts/usage-of-ttl-wire-on-linux/</link><pubDate>Sun, 18 Jul 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/usage-of-ttl-wire-on-linux/</guid><description>&lt;p&gt;虽然由于&lt;a href="http://0x3f.org/?p=1544"&gt;我的H108B&lt;/a&gt;没有TTL引脚而无法通过TTL线登入猫的&lt;a href="http://en.wikipedia.org/wiki/BusyBox"&gt;BusyBox&lt;/a&gt;系统，但TTL线在Linux下的使用方法仍然值得一叙，因为除此之外，它还有较为广泛的用途，例如为路由器刷&lt;a href="http://en.wikipedia.org/wiki/OpenWrt"&gt;OpenWRT&lt;/a&gt;系统等等。&lt;/p&gt;
&lt;p&gt;TTL转USB端子是目前较为常见的此类设备，这得益于它的简单易用和便携性。在这类设备上最常见的就是台湾的Prolific Technology生产的&lt;strong&gt;PL2303&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/fAc0kt6VmnFFTUY7IA-VrA?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/TEHb1u6n7TI/AAAAAAAABbU/FA7aEZPTn-A/s400/C360_2010-07-17%2011-07-17.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这种芯片的驱动已被编译进Linux内核，如果使用的是较新版本的内核，则使用该芯片的TTL转USB端子会被自动识别，通常为&lt;strong&gt;/dev/ttyUSB0&lt;/strong&gt;设备，使用&lt;strong&gt;lsusb&lt;/strong&gt;命令可以查看：&lt;/p&gt;
&lt;blockquote&gt;
[lenin@archer ~]$ lsusb
Bus 008 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 003: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
&lt;/blockquote&gt;
&lt;p&gt;将四根杜邦线连接到TTL转USB插头上，并接入相应设备的对应引脚。同一根线两端连接的引脚必须对应，另外，VCC引脚不能接线，否则会烧坏TTL转 USB芯片。&lt;/p&gt;
&lt;p&gt;在计算机上使用串口通讯程序进行操控，常见的串口通讯程序有：&lt;a href="http://en.wikipedia.org/wiki/Minicom"&gt;minicom&lt;/a&gt;，&lt;a href="http://en.wikipedia.org/wiki/Microcom"&gt;microcom&lt;/a&gt;，picocom，tinyserial，xgcom。&lt;/p&gt;
&lt;p&gt;以minicom为例，进入minicom的设置界面：&lt;/p&gt;
&lt;blockquote&gt;sudo minicom -s&lt;/blockquote&gt;
&lt;p&gt;先设置默认的通讯设备为ttyUSB0并设置硬件流控制（Hardware Flow Control）为No：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/YnqotA0Fo6Z883T7aKvDcg?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/TEMR710O6XI/AAAAAAAABb4/noM3E7ZEiuM/s800/2010-07-17.10%3A25%3A38.%E6%88%AA%E5%8F%96%E9%80%89%E5%8C%BA.01.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/G2S6THC9IqvBChZGkJfyqQ?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/TEMR7zBjcmI/AAAAAAAABb8/Z63_oSfjrnc/s400/2010-07-17.10%3A29%3A04.urxvt.01.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;保存为缺省设置：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/lY9b49woVJhLdkPJqViT3Q?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_ceUJ_lBTHzc/TEMR8Fjk3cI/AAAAAAAABcA/QnHscEzj1OY/s800/2010-07-17.10%3A29%3A35.%E6%88%AA%E5%8F%96%E9%80%89%E5%8C%BA.01.png" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>网通ADSL猫开启路由和自动拨号功能的方法之二</title><link>http://0x3f.org/posts/howto-enable-routing-and-auto-dialing-for-unicom-adsl-modem-2/</link><pubDate>Sun, 18 Jul 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-enable-routing-and-auto-dialing-for-unicom-adsl-modem-2/</guid><description>&lt;p&gt;之前提到过对华为HG522、HG527的超级用户的&lt;a href="http://0x3f.org/?p=1528"&gt;破解方法&lt;/a&gt;。网通附送的另一种猫，是&lt;strong&gt;中兴ZXV10 H108B&lt;/strong&gt;无线猫，体积更小，而且天线是内置的。&lt;/p&gt;
&lt;p&gt;上次的方法不能用在这个型号的猫上，但可以用&lt;strong&gt;ftp&lt;/strong&gt;的方式破解。以下步骤基于Linux，并只在硬件版本为&lt;strong&gt;V1.1.02&lt;/strong&gt;、软件版本为&lt;strong&gt;V1.1.02T18_N&lt;/strong&gt;的H108B上测试通过：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;使用&lt;strong&gt;普通用户&lt;/strong&gt;进入猫的设置页面并开启FTP服务，将用户名和密码均设为&lt;strong&gt;admin&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;连接ftp服务器：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
ftp 192.168.1.1
&lt;/blockquote&gt;
&lt;p&gt;输入用户名和密码，成功登录FTP服务器：&lt;/p&gt;
&lt;blockquote&gt;
[lenin@archer ~]$ ftp 192.168.1.1
Connected to 192.168.1.1.
220 Welcome to virtual FTP service.
Name (192.168.1.1:lenin): admin
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp&gt;
&lt;/blockquote&gt;
&lt;ol start="3"&gt;
&lt;li&gt;切换到&lt;strong&gt;/etc&lt;/strong&gt;目录并下载配置文件&lt;strong&gt;board.conf&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
cd ../
cd etc
get board.conf
&lt;/blockquote&gt;
&lt;p&gt;如下所示：&lt;/p&gt;
&lt;blockquote&gt;
ftp&gt; cd ../
250 Directory successfully changed.
ftp&gt; cd etc
250 Directory successfully changed.
ftp&gt; get board.conf
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for board.conf (39516 bytes).
226 File send OK.
39516 bytes received in 0.0496 seconds (796003 bytes/s)
ftp&gt;
&lt;/blockquote&gt;
&lt;ol start="4"&gt;
&lt;li&gt;在下载到本地的board.conf中查找&lt;strong&gt;right&lt;/strong&gt;，后跟&lt;strong&gt;0&lt;/strong&gt;表示超级用户，若为&lt;strong&gt;1&lt;/strong&gt;则表示普通用户，如下所示：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;row&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;&amp;#34;right&amp;#34;, &amp;#34;0&amp;#34;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;&amp;#34;username&amp;#34;, &amp;#34;bjcnchgw&amp;#34;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;&amp;#34;enable&amp;#34;, &amp;#34;1&amp;#34;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;&amp;#34;password&amp;#34;, &amp;#34;bjcnchgw72915767&amp;#34;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/row&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;row&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;&amp;#34;right&amp;#34;, &amp;#34;1&amp;#34;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;&amp;#34;username&amp;#34;, &amp;#34;user&amp;#34;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;&amp;#34;password&amp;#34;, &amp;#34;mypasswd&amp;#34;&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/row&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="5"&gt;
&lt;li&gt;在如下页面使用超级用户登录：&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
http://192.168.1.1/cnc.html
&lt;/blockquote&gt;
&lt;ol start="6"&gt;
&lt;li&gt;进入“&lt;strong&gt;网络&lt;/strong&gt;”→“&lt;strong&gt;宽带设置&lt;/strong&gt;”页面，删除所有“&lt;strong&gt;连接名称&lt;/strong&gt;”列出的连接（&lt;em&gt;其中，TR069是网通远程控制猫并修改超级用户密码的连接；INTERNET被设置成了桥接，所以不能实现路由功能；另外两个应该是用来屏蔽第三、四个LAN口的。所以要全部删除。&lt;/em&gt;），并创建新的连接：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/G5p8or5AvVumvFOr89XLqQ?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/TEHd0wXELFI/AAAAAAAABbs/gtxn0tKGyJM/s400/2010-07-17.19%3A48%3A30.%E6%88%AA%E5%8F%96%E9%80%89%E5%8C%BA.01.png" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Linux下pppoe连接建立后仍不能上网的问题</title><link>http://0x3f.org/posts/problem-on-pppoe-connections-on-linux/</link><pubDate>Sat, 10 Jul 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/problem-on-pppoe-connections-on-linux/</guid><description>&lt;p&gt;&lt;strong&gt;问题描述&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;pppoe可以连接，ifconfig可以看到ppp0接口，一切正常，只是不能上网。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决办法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用如下命令查看路由表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;route
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;正常情况下返回的结果中应该有如下内容：&lt;/p&gt;
&lt;blockquote&gt;
default * 0.0.0.0 U 0 0 0 ppp0
&lt;/blockquote&gt;
&lt;p&gt;如果没有，可手工添加：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;route add default dev ppp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果可以上网，就成功了。&lt;/p&gt;
&lt;p&gt;使用如下脚本在pppoe连接成功时自动添加路由表项：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; ifconfig ppp0 &amp;gt; /dev/null 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; route del default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; route add default dev ppp0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;将上述内容保存成名为&lt;strong&gt;01-route.sh&lt;/strong&gt;的文件，权限&lt;strong&gt;755&lt;/strong&gt;，放到&lt;strong&gt;/etc/ppp/ip-up.d&lt;/strong&gt;目录下。&lt;/p&gt;
&lt;p&gt;然后创建以下两个脚本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; ifconfig ppp0 &amp;gt; /dev/null 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PPPOE has already been switched on !&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;off
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo pon
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sleep &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /etc/ppp/ip-up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; ! ifconfig ppp0 &amp;gt; /dev/null 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PPPOE has already been switched off !&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo poff
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /etc/ppp/ip-down
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;分别命名为&lt;strong&gt;on&lt;/strong&gt;和&lt;strong&gt;off&lt;/strong&gt;并复制到环境变量PATH下，以后即可使用这两个脚本建立和注销pppoe连接。&lt;/p&gt;</description></item><item><title>网通ADSL猫开启路由和自动拨号功能的方法之一</title><link>http://0x3f.org/posts/howto-enable-routing-and-auto-dialing-for-unicom-adsl-modem-1/</link><pubDate>Sun, 04 Jul 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-enable-routing-and-auto-dialing-for-unicom-adsl-modem-1/</guid><description>&lt;p&gt;北京网通送的无线猫有的是华为HG522，有的是HG527，屏蔽了路由和PPPOE自动拨号功能，须使用超级用户登入才能使用这些功能。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;假设网关为默认的192.168.1.1，先使用普通用户登录，然后访问地址：&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
http://192.168.1.1/downloadconfigfile.conf
&lt;/blockquote&gt;
&lt;p&gt;下载该文件并搜索&lt;strong&gt;username&lt;/strong&gt;，找到超级用户的用户名和密码，如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;X_ATP_UserInfoInstance&lt;/span&gt; &lt;span class="na"&gt;InstanceID=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;Username=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;bjcnchgw&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;Userpassword=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;bjcnchgw27852654&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;Userlevel=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;2&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;Busy=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;LoginIP=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;在如下地址使用超级用户登录：&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
http://192.168.1.1/cnc.html
&lt;/blockquote&gt;
&lt;ol start="3"&gt;
&lt;li&gt;设置内容如下图：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/MwzSxgWShGMJmYJdSQRw8w?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/TDAy1kazOFI/AAAAAAAABa8/jRmlkSC4MaM/s400/32144754dc04625b375cf1d83f3587fc.media.812x604.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;终于不用再忍受公共网络了……&lt;/em&gt;&lt;/p&gt;</description></item><item><title>cd到目录下后自动ls的方法</title><link>http://0x3f.org/posts/howto-do-auto-listing-after-changing-directory/</link><pubDate>Sun, 20 Jun 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-do-auto-listing-after-changing-directory/</guid><description>&lt;p&gt;每cd到一个目录下就ls，这成了我的习惯。以下Bash函数和别名可以实现cd到一个目录下就自动执行ls命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cdl&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ls&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;cd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cdl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;将上述内容添加到用户主目录中的.bashrc中即可。&lt;/p&gt;</description></item><item><title>Linux下使用freetds连接SQL Server</title><link>http://0x3f.org/posts/connect-to-sqlserver-using-freetds-on-linux/</link><pubDate>Sun, 20 Jun 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/connect-to-sqlserver-using-freetds-on-linux/</guid><description>&lt;p&gt;&lt;a href="http://www.freetds.org"&gt;freetds&lt;/a&gt;是第三方、开源的数据库客户端和连接库，支持Sybase和Microsoft SQL Server，它最大的好处是允许非Windows平台的程序连接SQL Server。&lt;/p&gt;
&lt;p&gt;freetds的编译和安装命令如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./configure --with-tdsver&lt;span class="o"&gt;=&lt;/span&gt;8.0 --enable-msdblib
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;configure的这两个参数是必不可少的，否则可能无法连接SQL Server。&lt;/p&gt;
&lt;p&gt;安装后修改&lt;strong&gt;freetds.conf&lt;/strong&gt;（&lt;em&gt;一般应该在/usr/local/etc/freetds.conf&lt;/em&gt;），添加如下内容：&lt;/p&gt;
&lt;blockquote&gt;
[mysvr]
host = 10.1.29.40
port = 1433
tds version = 8.0
client charset = utf-8
&lt;/blockquote&gt;
&lt;p&gt;上述参数应根据实际情况修改。&lt;/p&gt;
&lt;p&gt;最后使用如下命令测试连接：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tsql -S mysvr -U sa -P &lt;span class="m"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;给公司产品做Linux下的安装包，把开发环境放在了Cygwin中，非常享受在全屏、半透明的mintty下敲命令。今天发现在Cygwin下也是可以编译安装Linux下的程序的，只是效率非常低下。故上述内容对Cygwin环境同样成立。&lt;/p&gt;</description></item><item><title>升级到wordpress3.0</title><link>http://0x3f.org/posts/after-upgrading-to-wordpress30/</link><pubDate>Sat, 19 Jun 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/after-upgrading-to-wordpress30/</guid><description>&lt;p&gt;昨天发现wordpress3.0已经发布，就顺手升级了。&lt;/p&gt;
&lt;p&gt;略看了一下更新内容，几乎没什么让我感兴趣的，但与MU版本的合并堪称WP历史上的一个里程碑，从此一套WP可以支持创建多个博客了。&lt;/p&gt;
&lt;p&gt;但我最近几度都想把博客换到dokuwiki下。&lt;/p&gt;
&lt;p&gt;自从&lt;a href="http://0x3f.org/?p=1455"&gt;开始用dokuwiki来组织知识和GTD&lt;/a&gt;以来，我对wiki产生了越来越深的痴迷，最主要的原因就是它可以用很简单的语法写出格式规整的文章，我几乎可以不用考虑排版布局而只需把注意力放在文章内容上就行了。而将wiki上的文章发到博客上时，还需要重写，比较浪费时间。&lt;/p&gt;
&lt;p&gt;但我最终放弃这个想法，最主要的原因是博客文章太多了，截至现在已经有五百多篇且大多是用HTML写的，难以转换。何况WP作为一个博客系统较wiki有着天生的优势，使用较为方便，如果用wiki来做博客，要做不少工作。&lt;/p&gt;</description></item><item><title>用JavaScript实现分页打印</title><link>http://0x3f.org/posts/howto-do-paged-printing-using-javascript/</link><pubDate>Sat, 19 Jun 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-do-paged-printing-using-javascript/</guid><description>&lt;p&gt;最近客户提的一个需求，要实现分页打印功能。公司产品对打印功能实现得不够好，排版全由程序生成，耦合度高，且不支持分页，需要用笨拙的方法变通。&lt;/p&gt;
&lt;p&gt;于是我对如何更好地实现分页打印产生了兴趣，Google了一下，整理了一个Demo：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;text/html;charset=utf-8&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt; &lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;print&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Noprint&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PageNext&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;page-break-after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;OBJECT&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;WebBrowser&lt;/span&gt; &lt;span class="na"&gt;classid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;CLSID:8856F961-340A-11D0-A96B-00C04FD705A2&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt; &lt;span class="na"&gt;VIEWASTEXT&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Noprint&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;document.all.WebBrowser.ExecWB(6,1)&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;button&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;打印&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;document.all.WebBrowser.ExecWB(7,1)&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;button&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;打印预览&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;document.all.WebBrowser.ExecWB(8,1)&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;button&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;页面设置&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Button4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;PageNext&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;雅游&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;旧院人称曲中，前门对武定桥，后门在钞库街。妓家鳞次，比屋而居。屋宇精洁，花木萧疏，迥非尘境。&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;到门则铜环半启，珠箔低垂;升阶则猧儿吠客，鹦哥唤茶；登堂则假母肃迎，分宾抗礼；&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;进轩则丫鬟毕妆，捧艳而出；坐久则水陆备至，丝肉竞陈；定情则目眺心挑，绸缪宛转。&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;纨绔少年，绣肠才子，无不魂迷色阵，气尽雌风矣。&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;妓家，仆婢称之曰娘，外人呼之曰小娘，假母称之曰娘儿。&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;有客称客曰姐夫，客称假母曰外婆。&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;PageNext&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;木兰花令·拟古决绝词&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;清·纳兰容若&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;人生若只如初见，何事秋风悲画扇。等闲变却故人心，却道故人心易变!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;骊山语罢清宵半，泪雨零铃终不怨。何如薄幸锦衣郎，比翼连枝当日愿!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个方法的好处是支持以低耦合的方式分页打印，同时支持只打印页面上指定的部分内容；缺点是由于使用了ActiveX，故只支持IE浏览器。&lt;/p&gt;</description></item><item><title>中转feedburner订阅数图标</title><link>http://0x3f.org/posts/howto-display-feedburner-subscription-image/</link><pubDate>Mon, 14 Jun 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-display-feedburner-subscription-image/</guid><description>&lt;p&gt;利用国外服务器中转feedburner的图标：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 将$fburl替换为自己的feedburner订阅数图片地址，然后将博客中的图片地址换成此脚本的URL即可
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$fburl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;http://feeds.feedburner.com/~fc/leninlee?bg=99CCFF&amp;amp;amp;fg=444444&amp;amp;amp;anim=0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$fbfl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;fb.gif&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fburl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$fp_local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fbfl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp_local&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;feof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp_local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp_local&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Location: &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$fbfl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;或者：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type: image/gif&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://feeds.feedburner.com/~fc/leninlee?bg=99CCFF&amp;amp;fg=444444&amp;amp;anim=0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>低碳生活：使用 cpufrequtils降低CPU温度</title><link>http://0x3f.org/posts/using-cpufrequtils-to-reduce-cpu-temperature/</link><pubDate>Fri, 11 Jun 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/using-cpufrequtils-to-reduce-cpu-temperature/</guid><description>&lt;p&gt;cpufrequtils可以根据不同的方案自动调节CPU的频率，从而达到在系统空闲时降低CPU温度、节省电力的目的。&lt;/p&gt;
&lt;p&gt;Archlinux官方wiki已经介绍得很明白了：&lt;a href="http://wiki.archlinux.org/index.php/Cpufrequtils_(简体中文)"&gt;&lt;a href="http://wiki.archlinux.org/index.php/Cpufrequtils_("&gt;http://wiki.archlinux.org/index.php/Cpufrequtils_(&lt;/a&gt;简体中文)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;使用后效果明显，CPU温度有所下降，下面是cpufrequtils在&lt;a href="http://0x3f.org/?tag=arch"&gt;Arch&lt;/a&gt;上的工作情况：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[lenin@archer ~]$ cpufreq-info
cpufrequtils 007: cpufreq-info (C) Dominik Brodowski 2004-2009
Report errors and bugs to cpufreq@vger.kernel.org, please.
analyzing CPU 0:
driver: acpi-cpufreq
CPUs which run at the same hardware frequency: 0 1
CPUs which need to have their frequency coordinated by software: 0
maximum transition latency: 10.0 us.
hardware limits: 800 MHz - 2.53 GHz
available frequency steps: 2.53 GHz, 2.53 GHz, 1.60 GHz, 800 MHz
available cpufreq governors: ondemand, performance
current policy: frequency should be within 800 MHz and 1.60 GHz.
The governor &amp;#34;ondemand&amp;#34; may decide which speed to use
within this range.
current CPU frequency is 800 MHz.
analyzing CPU 1:
driver: acpi-cpufreq
CPUs which run at the same hardware frequency: 0 1
CPUs which need to have their frequency coordinated by software: 1
maximum transition latency: 10.0 us.
hardware limits: 800 MHz - 2.53 GHz
available frequency steps: 2.53 GHz, 2.53 GHz, 1.60 GHz, 800 MHz
available cpufreq governors: ondemand, performance
current policy: frequency should be within 800 MHz and 1.60 GHz.
The governor &amp;#34;performance&amp;#34; may decide which speed to use
within this range.
current CPU frequency is 1.60 GHz.
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Inno Setup执行SQL脚本的方法</title><link>http://0x3f.org/posts/howto-execute-sql-scripts-in-inno-setup/</link><pubDate>Mon, 17 May 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-execute-sql-scripts-in-inno-setup/</guid><description>&lt;p&gt;作为和&lt;a href="http://zh.wikipedia.org/zh-cn/Nullsoft%E8%85%B3%E6%9C%AC%E5%AE%89%E8%A3%9D%E7%B3%BB%E7%B5%B1"&gt;NSIS&lt;/a&gt;并立的、两个最流行的免费Windows应用程序安装包制作工具之一，&lt;a href="http://en.wikipedia.org/wiki/Inno_Setup"&gt;Inno&lt;/a&gt;在学习难度上相对要低一些，非常适合对一些简单的桌面程序打包。但对于较复杂的安装过程，或者Web应用程序来说，我个人觉得不是Inno的强项。当然，既然Inno内嵌了&lt;a href="http://zh.wikipedia.org/zh-cn/Pascal"&gt;Pascal&lt;/a&gt;语言用以扩展功能，理论上不是不可以应付复杂的安装过程，但实现起来要复杂一些。&lt;/p&gt;
&lt;p&gt;比如对于在安装过程中连接数据库并执行SQL脚本这样的需求，使用&lt;a href="http://en.wikipedia.org/wiki/InstallShield"&gt;InstallShield&lt;/a&gt;应该会简单地多，而Inno却不支持直接操作数据库，并且相关的资料说明少之又少，还不如NSIS丰富，以至于我踏破铁鞋无觅处，最终却在NSIS的资料中找到了思路。&lt;/p&gt;
&lt;p&gt;主要的思路是，在安装过程中，调用数据库客户端连接数据库并执行SQL脚本，然后将执行结果或错误信息输出到文件中，最后通过分析这个文件来判断命令执行的结果。但是，既然是调用特定的客户端，那么对不同数据库的操作自然就有所区别，具体情况如下所述。&lt;/p&gt;
&lt;p&gt;首先在打包脚本的&lt;strong&gt;[Files]&lt;/strong&gt;段将必需的文件包含进来：&lt;/p&gt;
```ini
[Files]
Source: "D:\Development\MyDemoApp\code\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "D:\Development\MyDemoApp\sqlcmd.exe"; Flags: dontcopy
Source: "D:\Development\MyDemoApp\sqlcmd.rll"; Flags: dontcopy
Source: "D:\Development\MyDemoApp\mysql.exe"; Flags: dontcopy
Source: "D:\Development\MyDemoApp\script_mssql.sql"; Flags: dontcopy
Source: "D:\Development\MyDemoApp\script_mysql.sql"; Flags: dontcopy
Source: "D:\Development\MyDemoApp\script_oracle.sql"; Flags: dontcopy
```
&lt;p&gt;在SQL Server中执行脚本的代码片断：&lt;/p&gt;
```pascal
function ExecScriptInMSSQL(DBHost, DBLogin, DBPass, DBName: String): Boolean;
var
ConnectExe: String;
ConnectParam: String;
begin
{解压临时文件}
ExtractTemporaryFile('sqlcmd.exe');
ExtractTemporaryFile('sqlcmd.rll');
ExtractTemporaryFile('script_mssql.sql');
{构造数据库连接字符串}
ConnectExe := ExpandConstant('{tmp}') + '\sqlcmd.exe';
ConnectParam := ' -S ' + DBHost
+ ' -U ' + DBLogin
+ ' -P ' + DBPass
+ ' -d ' + DBName
+ ' -i script_mssql.sql -o '
+ ExpandConstant('{tmp}') + '\dbstatus.txt';
{建立数据库连接并执行脚本}
if Exec(ConnectExe, ConnectParam, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then begin
Result := ResultCode = 0;
LoadStringFromFile(ExpandConstant('{tmp}') + '\dbstatus.txt', StatusString);
if StatusString &lt;&gt; '' then begin
MsgBox(StatusString, mbError, MB_OK);
Result := False;
end else begin
Result := True;
end;
end else begin
MsgBox('Database update failed:'#10#10 + SysErrorMessage(ResultCode), mbError, MB_OK);
Result := False;
end;
end;
```
&lt;p&gt;在MySQL中执行脚本的代码片断：&lt;/p&gt;</description></item><item><title>FreeArc：兼顾压缩比率与效率的压缩程序</title><link>http://0x3f.org/posts/freearc/</link><pubDate>Sun, 09 May 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/freearc/</guid><description>&lt;p&gt;&lt;a href="http://freearc.org/"&gt;FreeArc&lt;/a&gt;的特点在于它在压缩比率与效率上取得了一个很好的平衡。传统的压缩程序则多偏重一点，要么占用系统资源低、速度快，但压缩比率小，如ZIP、RAR；要么压缩比率高，但占用系统资源大、速度慢，如7z。 &lt;/p&gt;
&lt;p&gt;把RAR归于前者只是相对而言，除了WinZip，没有哪个压缩工具能取得像WinRAR那样的成功。之所以能做到这一点，是因为WinRAR不但继承了WinZip易用的优点，还具有对多种压缩算法广泛的兼容度，最重要的是，RAR压缩算法在效率与比率之间取得了一个非常好的平衡。凭借这些优势，WinRAR一举推翻了WinZip的王座，直到现在，它都是这个领域值得学习的榜样。 &lt;/p&gt;
&lt;p&gt;早在7-Zip刚刚推出的时候，我就用过它。在压缩比率上，7z较RAR有着明显的优势，但在系统资源占用和压缩速度上，7z的表现非常不理想。最糟糕的是，如果你的机器配置较低，再加上你使用Windows系统，并且尤其喜欢使用图形界面的压缩工具，那7-zip对你来说就是一场恶梦，我曾经有过压缩一个较大的文件时进度条半天都不移动的经历。当然，在Windows命令行或Linux的终端中使用7-zip情况要好很多。此外，随着7-zip自身的完善和电脑配置的更新换代，这些劣势对7-zip普及的限制正逐渐弱化，事实上，我倾向于推荐用7-zip取代WinRAR，因为前者免费且有较大的压缩比率，而后者是收费的。 &lt;/p&gt;
&lt;p&gt;上周偶然发现的FreeArc，它的主页上居然宣称比最好的压缩工具都快1.5到3倍，并且同时拥有超高的压缩比率。于是我拿7-zip与之作了几个粗略的对比测试，发现虽然没有宣称的那么夸张，但在压缩同样的文件并使用同样的压缩级别时，FreeArc均比7-zip快一些，而压缩比率却要稍高于后者。甚至对于某些格式的文件，FreeArc的“普通”级别的压缩比率都比7-zip“最高”级别的大。 &lt;/p&gt;
&lt;p&gt;鉴于7-zip是资源占用大户，我非常怀疑在效率上FreeArc较WinRAR会有什么优势，更遑论快上1.5到3倍，但它的效率高于7-zip却是一个不争的事实，何况还有更高的压缩比率。此外，这次的测试中使用的操作系统和7-zip都是64位的，而FreeArc却是32位的，因此在效率的比试上会有不公平的地方。 &lt;/p&gt;
&lt;p&gt;当然，FreeArc自身的缺点也很大： &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;尚无64位版本&lt;/li&gt;
&lt;li&gt;只支持Windows和Linux系统&lt;/li&gt;
&lt;li&gt;不支持多卷压缩（分割压缩）&lt;/li&gt;
&lt;li&gt;其它一些问题&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果能在较短的时间内解决这些问题，我认为FreeArc还是很有前景的。&lt;/p&gt;</description></item><item><title>SSL证书生成方法</title><link>http://0x3f.org/posts/howto-create-ssl-certificates/</link><pubDate>Mon, 03 May 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/howto-create-ssl-certificates/</guid><description>&lt;p&gt;一般情况下，如果能找到可用的证书，就可以直接使用，只不过会因证书的某些信息不正确或与部署证书的主机不匹配而导致浏览器提示证书无效，但这并不影响使用。&lt;/p&gt;
&lt;p&gt;需要手工生成证书的情况有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;找不到可用的证书&lt;/li&gt;
&lt;li&gt;需要配置双向SSL，但缺少客户端证书&lt;/li&gt;
&lt;li&gt;需要对证书作特别的定制&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;首先，无论是在Linux下还是在Windows下的Cygwin中，进行下面的操作前都须确认已安装OpenSSL软件包。&lt;/p&gt;
&lt;p&gt;1. 创建根证书密钥文件&lt;strong&gt;root.key&lt;/strong&gt;：&lt;/p&gt;
```
openssl genrsa -des3 -out root.key
```
&lt;p&gt;输出内容为：&lt;/p&gt;
```
[lenin@archer ~]$ openssl genrsa -des3 -out root.key
Generating RSA private key, 512 bit long modulus
.................++++++++++++
..++++++++++++
e is 65537 (0x10001)
Enter pass phrase for root.key: ← 输入一个新密码
Verifying - Enter pass phrase for root.key: ← 重新输入一遍密码
```
&lt;p&gt;2. 创建根证书的申请文件&lt;strong&gt;root.req&lt;/strong&gt;：&lt;/p&gt;
```
openssl req -new -key root.key -out root.req
```
&lt;p&gt;输出内容为：&lt;/p&gt;
```
[lenin@archer ~]$ openssl req -new -key root.key -out root.req
Enter pass phrase for root.key: ← 输入前面创建的密码
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN ← 国家代号，中国输入CN
State or Province Name (full name) [Some-State]:BeiJing ← 省的全名，拼音
Locality Name (eg, city) []:BeiJing ← 市的全名，拼音
Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyCompany Corp. ← 公司英文名
Organizational Unit Name (eg, section) []: ← 可以不输入
Common Name (eg, YOUR name) []: ← 此时不输入
Email Address []:admin@mycompany.com ← 电子邮箱，可随意填&lt;/p&gt;</description></item><item><title>强大的工具函数库：php.js</title><link>http://0x3f.org/posts/phpjs/</link><pubDate>Sat, 24 Apr 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/phpjs/</guid><description>&lt;p&gt;PHP最大的特点在于它拥有一个丰富、灵活、强大的函数库，因此得以机动灵活成为软件开发语言中的轻骑兵。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://phpjs.org/"&gt;php.js&lt;/a&gt;是一个用Javascript实现的函数库，它试图用Javascript最大程度地重写PHP的函数库。相对于JQuery、ExtJS这些Javascript库，php.js不并致力于为AJAX、DOM和界面开发提供一揽子解决方案，它只是将PHP函数的强大和简便带到前端开发中来，由于JQuery这样的库并不旨在提供完全的Javascript开发标准和手段，实际上，它弥补了这些高端的工具库与低端的Javascript开发之间的一个空白。&lt;/p&gt;
&lt;p&gt;对于熟悉PHP的人尤其是PHP程序员来说，使用php.js是几乎不需要切换思维方式的。&lt;/p&gt;
&lt;p&gt;这是使用php实现的日期格式校验函数：&lt;/p&gt;
&lt;p&gt;
```php
function IsValidDate($strDate, $strFormat='Y-m-d') {
$strDate = trim($strDate);
$unixTime = strtotime($strDate);
$strNewDate = date($strFormat, $unixTime);
return $strDate == $strNewDate;
}
```
&lt;/p&gt;
&lt;p&gt;这是使用php.js实现的日期格式校验函数：&lt;/p&gt;
&lt;p&gt;
```javascript
function IsValidDate(strDate, strFormat) {
strDate = trim(strDate);
var unixTime = strtotime(strDate);
var strNewDate = date(strFormat, unixTime);
return strDate == strNewDate;
}
```
&lt;/p&gt;</description></item><item><title>在Vim中检查语法和执行代码</title><link>http://0x3f.org/posts/syntax-checking-and-code-executing-in-vim/</link><pubDate>Sat, 17 Apr 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/syntax-checking-and-code-executing-in-vim/</guid><description>&lt;p&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/SaV494hGreI/AAAAAAAAAzY/xExf7CzGyv0/s800/the-mug-of-vi.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;《&lt;a href="http://www.pragprog.com/the-pragmatic-programmer"&gt;The Pragmatic Programmer&lt;/a&gt;》是本好书，虽然中文译名极为恶俗。为践行书中提到的&lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY原则&lt;/a&gt;，我开始反思平时编码时总是重复出现的问题，其中之一就是很低级的语法错误，有时忘了语句最后的分号，有时忘了声明变量，凡此种种，不一而足。&lt;/p&gt;
&lt;p&gt;相对于IDE，我更喜欢Vim，这也是语法错误没有检查出来的原因。因此就产生了给Vim添加语法检查功能的需求。下面是检查PHP代码的vimrc内容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;#34; Check the syntax of a PHP file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;CheckPHPSyntax&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &amp;amp;&lt;span class="k"&gt;filetype&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;php&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;echohl&lt;/span&gt; &lt;span class="nx"&gt;WarningMsg&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;This is not a PHP file !&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;echohl&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;setlocal&lt;/span&gt; &lt;span class="nx"&gt;makeprg&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;\ &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;\ &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;\ &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;\ &lt;span class="nx"&gt;html_errors&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;off&lt;/span&gt;\ %
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;setlocal&lt;/span&gt; &lt;span class="nx"&gt;errorformat&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;%&lt;span class="nx"&gt;m&lt;/span&gt;\ &lt;span class="nx"&gt;in&lt;/span&gt;\ %&lt;span class="nx"&gt;f&lt;/span&gt;\ &lt;span class="nx"&gt;on&lt;/span&gt;\ &lt;span class="nx"&gt;line&lt;/span&gt;\ %&lt;span class="nx"&gt;l&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;echohl&lt;/span&gt; &lt;span class="nx"&gt;WarningMsg&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Syntax checking output:&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;echohl&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &amp;amp;&lt;span class="nx"&gt;modified&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;silent&lt;/span&gt; &lt;span class="nx"&gt;write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;silent&lt;/span&gt; &lt;span class="nx"&gt;make&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;clist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="k"&gt;filetype&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;CheckPHPSyntax&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;au&lt;/span&gt; &lt;span class="k"&gt;filetype&lt;/span&gt; &lt;span class="nx"&gt;php&lt;/span&gt; &lt;span class="nx"&gt;imap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ESC&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;:&lt;span class="nx"&gt;call&lt;/span&gt; &lt;span class="nx"&gt;CheckPHPSyntax&lt;/span&gt;&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;以上脚本为Vim添加了一个检查PHP语法错误的函数和两个快捷键映射，此后可按F5键即时检查当前Buffer中的PHP当面的语法。和网上其它同类的函数相比，这个函数的优点在于改进了检查结果的显示，使用silent命令隐藏了所有不必要的输出。&lt;/p&gt;</description></item><item><title>Buuf-Deuce：搞怪的图标主题</title><link>http://0x3f.org/posts/buuf-deuce-icon-theme/</link><pubDate>Sat, 10 Apr 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/buuf-deuce-icon-theme/</guid><description>&lt;p&gt;发现这个&lt;a href="http://djany.deviantart.com/art/Gnome-Buuf-Deuce-1-1-R8-73339997"&gt;图标主题&lt;/a&gt;有段时间了，但直到今天偶然重新启用它，才突然觉得这套色调灰暗、风格搞怪的图标其实整体效果很好，很有个性，且极为闷骚，实为标榜非主流人士居家旅行必备。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/dGjc_mAUv2rQOLRDLlUZKw?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/S8CQfF_kpbI/AAAAAAAABZ8/UV3W7nTx3vA/s800/Gnome_Buuf_Deuce_1_1_R8_by_djany.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Archlinux升级到GNOME2.30后的光标主题问题</title><link>http://0x3f.org/posts/problem-about-icon-theme-on-gnome230/</link><pubDate>Sun, 04 Apr 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/problem-about-icon-theme-on-gnome230/</guid><description>&lt;p&gt;Archlinux下的GNOME升级到2.30后，若启用了Compiz，则光标主题只能使用X默认的主题，无法自定义。尚不清楚是GNOME新版本自身的问题还是仅限于Arch发行版。&lt;/p&gt;
&lt;p&gt;在官方提供解决方案或更新之前，可以先使用Xdefault或Xresource文件实现。&lt;/p&gt;
&lt;p&gt;以后者为例，编辑用户主目录下的&lt;strong&gt;.Xresource&lt;/strong&gt;，在文件最后添加如下内容：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Xcursor.theme: faber-anthracite-shd-m&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;faber-anthracite-sdh-m&lt;/strong&gt;是我使用的光标主题的文件夹名。&lt;/p&gt;
&lt;p&gt;然后执行如下命令：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;xrdb ~/.Xresource&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最后注销并重新登录即可。&lt;/p&gt;</description></item><item><title>phpsh：PHP的交互式解释器</title><link>http://0x3f.org/posts/phpsh/</link><pubDate>Mon, 29 Mar 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/phpsh/</guid><description>&lt;p&gt;时常需要测试一些简短的代码是否能得到需要的结果，如果去写测试脚本再执行，显然太麻烦。虽然PHP自身也支持通过&lt;strong&gt;&lt;em&gt;-a&lt;/em&gt;&lt;/strong&gt;参数启动交互模式，但功能较为局限。如果PHP有像&lt;a href="http://bpython-interpreter.org/"&gt;bpython&lt;/a&gt;那样的交互式解释器，就太好了。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.phpsh.org/"&gt;phpsh&lt;/a&gt;就是这样一个工具，它是由&lt;a href="http://zh.wikipedia.org/wiki/Facebook"&gt;facebook&lt;/a&gt;的开发者用Python实现的PHP的交互式解释器，并具备以下特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;命令行历史回溯&lt;/li&gt;
&lt;li&gt;tab键自动补全&lt;/li&gt;
&lt;li&gt;快速文档索引&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>使用cx_Freeze的distutils脚本打包Python程序</title><link>http://0x3f.org/posts/cx-freeze/</link><pubDate>Fri, 26 Mar 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/cx-freeze/</guid><description>&lt;p&gt;cx_Freeze打包Python程序的命令基本格式如下：&lt;/p&gt;
&lt;p&gt;
```python
cxfreeze main.py --target-dir appdir
```
&lt;/p&gt;
&lt;p&gt;它表示把脚本main.py或以main.py为程序入口的程序打包并导出到当前路径中名为&lt;strong&gt;appdir&lt;/strong&gt;的目录中。&lt;/p&gt;
&lt;p&gt;对于Windows下的GUI应用程序，以上面的命令导出后，运行时会弹出&lt;strong&gt;cmd&lt;/strong&gt;命令行的黑窗口，须加上如下命令中的参数：&lt;/p&gt;
&lt;p&gt;
```python
cxfreeze main.py --target-dir appdir --base-name=win32gui
```
&lt;/p&gt;
&lt;p&gt;对于比较复杂的程序，cx_Freeze支持&lt;a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/charm-19/"&gt;distutils&lt;/a&gt;格式的打包脚本，当然，彼此之间在引入的模块和支持的参数上还是有差别的。&lt;/p&gt;
&lt;p&gt;cx_Freeze的文档中有其支持的全部命令参数及说明，写到setup.py脚本中时，所有参数中的&lt;strong&gt;-&lt;/strong&gt;符号应换成下划线。&lt;/p&gt;
&lt;p&gt;我的setup.py内容大致如下：&lt;/p&gt;
&lt;p&gt;
```python
#!/usr/bin/python
# -*- coding: utf-8 -*-
from cx_Freeze import setup,Executable
includefiles = [('settings.ini.jctest','settings.ini')
,'README.mkd']
includes = []
excludes = ['Tkinter']
packages = ['sqlalchemy.engine', 'sqlalchemy.orm', 'sqlalchemy.dialects.mssql']
setup(
name = 'pyutil',
version = '0.1',
description = 'A general enhancement utility for XXX',
author = 'Lenin Lee',
author_email = 'lenin.lee@xxx.com',
options = {'build_exe':{'excludes':excludes,'packages':packages,'include_files':includefiles}},
executables = [Executable('jcitk.py')
, Executable('jcvfd.py')
, Executable('jcvdupcr.py')
, Executable('jcddupcr.py')
, Executable('jcclostfd.py')
, Executable('jcvcard.py')
, Executable('jcvcardii.py')
, Executable('jcclostsoid.py')]
)
```
&lt;/p&gt;</description></item><item><title>开始玩儿茶道</title><link>http://0x3f.org/posts/starting-tea-ceremony/</link><pubDate>Sat, 20 Mar 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/starting-tea-ceremony/</guid><description>&lt;p&gt;前年买了个倒把小西施开始喝茶，渐渐地就觉得喝茶的趣味一半在茶，一半在泡。这周买了茶盘、茶道组等一应物件儿，直到周五晚上才有时间过把瘾。怕睡不着觉，没敢泡生茶，新开了一饼易武大树熟茶。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/2OI8UYBIqMUejiDCtL3JKg?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/S6OqNZV5xgI/AAAAAAAABVg/nipIKJWV6xk/s400/%E8%8C%B6%E9%81%93%20002.JPG" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>SQL Server的自定义函数：统计两日期之间工作日的数量</title><link>http://0x3f.org/posts/counting-days-between-dates-in-sqlserver/</link><pubDate>Sat, 13 Mar 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/counting-days-between-dates-in-sqlserver/</guid><description>&lt;p&gt;前段时间工作中遇到的一个需求，要求计算两个日期之间工作日的数量，即排除期间所有的周六和周日之后的天数。&lt;/p&gt;
&lt;p&gt;在网上找到一个自定义函数，原函数有些小问题，例如如果传入的截止日期如果有时间且足够大，则计算结果可能出错，修正后代码如下：&lt;/p&gt;
&lt;p&gt;
```sql
--函数：类似datediff，不统计期间所有的周六和周日
if exists (select * from dbo.sysobjects where id=object_id(N'[dbo].[f_WorkDay]') and xtype in (N'FN',N'IF',N'TF'))
drop function [dbo].[f_WorkDay]
GO
CREATE FUNCTION f_WorkDay(
@dt_begin datetime,
@dt_end datetime
)RETURNS int
AS
BEGIN
DECLARE @workday int,@i int,@bz bit,@dt datetime
set @dt_begin = convert(datetime, convert(nvarchar(32), @dt_begin, 23))
set @dt_end = convert(datetime, convert(nvarchar(32), @dt_end, 23))
IF @dt_begin&gt;@dt_end
SELECT @bz=1,@dt=@dt_begin,@dt_begin=@dt_end,@dt_end=@dt
ELSE
SET @bz=0
SELECT @i=DATEDIFF(Day,@dt_begin,@dt_end),@workday=@i/7*5,@dt_begin=DATEADD(Day,@i/7*7,@dt_begin)
WHILE @dt_begin&lt;@dt_end
BEGIN
SELECT @workday=CASE WHEN (@@DATEFIRST+DATEPART(Weekday,@dt_begin)-1)%7 BETWEEN 1 AND 5 THEN @workday+1 ELSE @workday END,@dt_begin=@dt_begin+1
END
RETURN(CASE WHEN @bz=1 THEN -@workday ELSE @workday END)
END
GO
```
&lt;/p&gt;</description></item><item><title>Python控制外部进程的灵异事件</title><link>http://0x3f.org/posts/supernatural-phenomenon-of-controlling-external-processes-in-python/</link><pubDate>Mon, 08 Mar 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/supernatural-phenomenon-of-controlling-external-processes-in-python/</guid><description>&lt;p&gt;春节前的一段时间，重新拾起近一年没动过的&lt;a href="http://0x3f.org/?tag=foreverfantasy"&gt;ForeverFantasy&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;虽然一年内没什么更新，但是我却一直都在用，基本上只限于将用Vim写好的&lt;a href="http://en.wikipedia.org/wiki/Markdown"&gt;Markdown&lt;/a&gt;格式的文档转换成HTML。&lt;/p&gt;
&lt;p&gt;重写了相当一部分代码，较大程度地改变了界面布局，突然发现经过一年的沉淀，对&lt;a href="http://en.wikipedia.org/wiki/WxPython"&gt;wxPython&lt;/a&gt;的理解增进了不少，开发起来比起去年这个时候清楚了很多。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/bNRGQr0g6aLuqDUm8EQ6mg?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_ceUJ_lBTHzc/S5UYPQmTAzI/AAAAAAAABUc/znMRxXuE8dE/s400/2010-03-08.23%3A27%3A03.%E5%B7%A5%E4%BD%9C%E5%8C%BA%201.01.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这些天来一直坚持着每天或多或少的做一些，如果说有什么主要的进展的话，那就是界面的重构，以及昨天实现了调用Vim编辑文档并回收文档内容的功能。&lt;/p&gt;
&lt;p&gt;ForeverFantasy和Vim协同的一个最大的问题就是如何判断Vim已经退出。Python调用外部程序的方法有很多，比如传统的&lt;a href="http://docs.python.org/library/commands.html"&gt;commands&lt;/a&gt;模块、&lt;a href="http://docs.python.org/library/os.html"&gt;os&lt;/a&gt;.system()等，&lt;a href="http://docs.python.org/library/subprocess.html"&gt;subprocess&lt;/a&gt;是致力于替代这些旧有的方式的一个模块，它的一个特点是可以在启动一个外部程序作为子进程后还能监控这个进程的运行状态。这为ForeverFantasy在Vim退出后回收文档内容提供了更简捷的途径。&lt;/p&gt;
&lt;p&gt;下面的代码可以说明如何使用subprocess运行外部程序并监控运行状态：&lt;/p&gt;
&lt;p&gt;
```python
import subprocess
process = subprocess.Popen('gvim', shell=True)
status = process.poll()
if 0 == status:
print 'The external program exited.'
if status is None:
print 'The external program is still running.'
```
&lt;/p&gt;
&lt;p&gt;理论上，可以拿实例process的poll()方法监视进程的运行状态，而且这一点在Windows上也确实可以做到，但是到了Linux下，诡异的事出现了，即使刚刚打开gvim，poll()方法也会马上返回一个0，同时process.pid的值总是和实际在运行的那个gvim进程的pid的值差3，而且在虚拟终端中输入gvim命令也不会阻塞终端，就像别的命令加上“&lt;strong&gt;&amp;amp;&lt;/strong&gt;”符号的效果一样。尝试用&lt;a href="http://en.wikipedia.org/wiki/Strace"&gt;strace&lt;/a&gt;跟踪gvim的运行，试图找到问题原因，无果。我猜想可能/usr/bin/gvim是一个跳板，它启动后会启动一个新的gvim进程。总之，这个方法在Linux下是行不通的。&lt;/p&gt;
&lt;p&gt;因此我觉得只能另寻出路了，既然不能监控gvim进程，那就监控gvim进程所编辑的文件，只要这个文件不被任何进程占用，就可以判定gvim已退出。这一点，在Linux下易如反掌，不用说，&lt;a href="http://en.wikipedia.org/wiki/Lsof"&gt;lsof&lt;/a&gt;当仁不让。&lt;/p&gt;
&lt;p&gt;用&lt;strong&gt;commands.getstatusoutput('lsof file.txt')&lt;/strong&gt;测试发现，如果文件file.txt被某进程占用，则返回的状态值为0，反之，返回256。&lt;/p&gt;
&lt;p&gt;最终，我在程序中使用了两种判断方式，在Windows平台使用subprocess跟踪gvim.exe进程，而在Linux及Unix平台使用lsof检查文档占用情况。&lt;/p&gt;
&lt;p&gt;剩下的就是进行这个判断的时间问题了。&lt;/p&gt;
&lt;p&gt;很显然，如果在子进程被启动后马上使用while循环不停的检查，一来必须使用多线程，二来系统资源占用也会很高。这时就需要利用wxPython的事件机制了，当ForeverFantasy启动Gvim时，主窗口失去焦点，而当Gvim退出时，ForeverFantasy又会获得焦点，只要能在ForeverFantasy窗口获得焦点时做一次检查即可。不过，在选择最合适的事件的问题上，又是一波三折。&lt;/p&gt;
&lt;p&gt;在wxPython的&lt;a href="http://www.wxpython.org/docs/api/frames.html"&gt;API&lt;/a&gt;文档中没有找到&lt;a href="http://wiki.wxpython.org/ListOfEvents"&gt;事件列表&lt;/a&gt;，倒是在&lt;a href="http://wiki.wxpython.org"&gt;Wiki&lt;/a&gt;中找到了。顾名思义，觉得wx.EVT_SET_FOCUS比较靠谱，但试用失败，看API中关于FocusEvent的说明，这个事件适用于窗口控件；然后又试了wx.EVT_CHILD_FOCUS，只有在窗口包含的控件中有获得焦点的情况才会触发；最后才发现&lt;strong&gt;wx.EVT_ACTIVATE&lt;/strong&gt;，这个事件会在窗口失去焦点和获得焦点时各触发一次，使用GetActive()方法可以判断是获得焦点还是失去焦点。&lt;/p&gt;
&lt;p&gt;完成与Vim的协同使ForeverFantasy在我手上由原来单纯的格式转换工具进化为基本可用的文档编辑器，就算是&lt;strong&gt;Milestone 2&lt;/strong&gt;吧。&lt;/p&gt;
&lt;p&gt;此外，还有一些小的经验：&lt;/p&gt;
&lt;p&gt;1. 调用非环境变量下的程序，即命令中必须带程序所在的路径时，应当将程序所在目录的完整路径以自然字符串的形式传递给subprocess.Popen类的构造方法的cwd参数，即如下所示：&lt;/p&gt;
&lt;p&gt;
```python
process = subprocess.Popen('gvim.exe', cwd=r'C:\program files\vim\vim72', shell=True)
```
&lt;/p&gt;
&lt;p&gt;这样可以有效避免路径中的空格和特殊字符对命令执行的影响。&lt;/p&gt;
&lt;p&gt;2. Vim编辑一个文档时，实际操作的是一个临时文件，而不是原文件，这个临时文件与原文件同路径，名称为在原文件名的基础上，前面加一个句点，后面加后缀“.swp”。应该用lsof监控这个临时文件，才可以判断出编辑该文档的Vim进程的运行状态。由于对于不存在的文件使用lsof命令的返回值也是256，故可以同时判断临时文件和原文件的占用情况，这样就为对其它编辑器的支持奠定了基础。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2010-03-10 Wednesday 22:52:13 更新&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;感谢KL童鞋和依云童鞋指教，果然加上&lt;strong&gt;-f&lt;/strong&gt;参数就可以了。&lt;/p&gt;</description></item><item><title>Vim的终极自动补全插件：NeoComplCache</title><link>http://0x3f.org/posts/neocomplcache-vim/</link><pubDate>Sat, 27 Feb 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/neocomplcache-vim/</guid><description>&lt;p&gt;&lt;img src="http://lh3.ggpht.com/_ceUJ_lBTHzc/SaV494hGreI/AAAAAAAAAzY/xExf7CzGyv0/s800/the-mug-of-vi.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;关于自动补全，最初用的是&lt;a href="http://www.vim.org/scripts/script.php?script_id=1643"&gt;SuperTab&lt;/a&gt;，那个时候Vim的自动补全插件寥寥无几，也就SuperTab比较有名。不过实际使用过程中这个插件给我的体验不是很好，原因是补全的准确度不高。&lt;/p&gt;
&lt;p&gt;后来出了一个新插件，&lt;a href="http://www.vim.org/scripts/script.php?script_id=1879"&gt;AutoComplPop&lt;/a&gt;，功能和使用都很简单。但是很快我就又用回SuperTab，原因是AutoComplPop在输入的同时实时地查询匹配的关键词，导致输入极不流畅，效率很低。&lt;/p&gt;
&lt;p&gt;一直就这么凑合着用着SuperTab，随着这个插件版本的更新，旧功能不断地完善，新功能也接二连三地引入，SuperTab在匹配关键词的准确度上有了一些改善，但是新的问题又出现了。SuperTab后来加入一个新功能，对于程序源文件，可以在其引入的文件以及API文件中匹配关键词。比如假设我当前正在编辑a.php，在a.php中有&lt;strong&gt;include 'b.php';&lt;/strong&gt;这样的语句，当我输入&lt;strong&gt;array&lt;/strong&gt;并按下Tab键时，SuperTab不但会在当前文件中查询所有匹配项，还会到b.php中查询，如果配置过vim、指定一个包含了php的API的文件，则SuperTab还会自动从这个文件中查询匹配项。按理说这个功能的理念很好，但问题就在于SuperTab做的是实时查询，如果源文件中包含的文件较多，各个文件又较大，问题就显而易见了。我不得不在写程序时小心地使用Tab键，否则有时就会出现按一下Tab键然后等着Vim在那狂搜的情况。&lt;/p&gt;
&lt;p&gt;前两天发现了&lt;a href="http://www.vim.org/scripts/script.php?script_id=2620"&gt;NeoComplCache&lt;/a&gt;，光看名字就让我有点儿兴奋，一般使用缓存的速度都很快。这个插件会在Vim打开文件的时候对上下文作一个索引，并把索引结果保存到缓存中。同时，文件更改的内容会在保存的时候被索引。此外，NeoComplCache支持多种关键词索引模式，例如它会判断当前路径下的文件或目录的名字是否匹配补全条件，也可以从缓存的程序语言API中匹配补全条件。到此为止，它就解决了SuperTab和AutoComplPop共同的效率问题，并具备它们各自的长处。看了一遍文档，发现这个插件的功能比较细致，大概有以下一些特点：&lt;/p&gt;
&lt;p&gt;1、使用缓存，自动补全时效率高；
2、生成的关键词列表准确；
3、支持下划线分割的关键词，如apple_boy_cat，就可以只输入a_b_c，然后补全；
4、支持驼峰格式匹配关键词，如AppleBoyCat，就可以只输入ABC，然后补全；
5、既可以像AutoComplPop那样在Vim中输入的同时自动弹出补全列表，又可以自定义快捷键手动触发；
6、支持从文件名和目录名中匹配补全条件；
7、对于程序源文件，支持从语言API中匹配补全条件；&lt;/p&gt;
&lt;p&gt;NeoComplCache的缺点是文档不全，虽然从只言片语中发现它还支持Snippet，但从文档中没有找到足够的有用信息。加之一直用&lt;a href="http://www.vim.org/scripts/script.php?script_id=2540"&gt;SnipMate&lt;/a&gt;感觉不错，所以目前还是用它来实现snippet功能。&lt;/p&gt;
&lt;p&gt;这就有个搭配问题：虽然NeoComplCache不存在补全时的效率问题，但我仍然打算只在需要补全时才用快捷键触发此功能，最主要的原因是我既希望用Tab键触发SnipMate的代码块补全功能，又希望修SuperTab那样用Tab选择补全列表中的选项。也就是要达到只用Tab键就可以完成打开自动补全列表、补全列表选项选择和SnipMate代码块替换的效果。但是，如果将Tab映射到触发自动补全，则补全列表选择和SnipMate均无法使用Tab，反之亦然。&lt;/p&gt;
&lt;p&gt;所以我想如果能让NeoComplCache、SuperTab、SnipMate和谐共存，那问题就解决了，几经摸索，终于找到了办法：&lt;/p&gt;
&lt;p&gt;1、设置NeoComplCache不自动弹出补全列表，即在vimrc中加入：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;let g:NeoComplCache_DisableAutoComplete = 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;2、由于NeoComplCache在手工模式下使用快捷键组合&lt;code&gt;&amp;lt;C-X&amp;gt;&amp;lt;C-U&amp;gt;&lt;/code&gt;打开补全列表，故设置SuperTab的默认补全操作为&lt;code&gt;&amp;lt;C-X&amp;gt;&amp;lt;C-U&amp;gt;&lt;/code&gt;，即在vimrc中加入：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;let g:SuperTabDefaultCompletionType = '&lt;code&gt;&amp;lt;C-X&amp;gt;&amp;lt;C-U&amp;gt;&lt;/code&gt;'&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这样，NeoComplCache只负责补全关键词缓存的生成，SuperTab控制Tab键的行为并在需要触发补全操作时打开补全列表、进而在列表中的选项间移动焦点，而当光标前的关键词是snippet时，SnipMate会被优先调用并完成代码块的替换。&lt;/p&gt;
&lt;p&gt;就在写这篇文章的时候，我突然觉得NeoComplCache自动弹出补全列表+SnipMate的方式也挺好，只是这样就不能用Tab键选择列表中的选项了。&lt;/p&gt;
&lt;h3 id="相关阅读"&gt;相关阅读：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/replace-youcompleteme-with-neocomplete/"&gt;用neocomplete换掉了YouCompleteMe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://0x3f.org/post/make-youcompleteme-ultisnips-compatible/"&gt;How to Make YouCompleteMe Compatible with UltiSnips&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>SQLAlchemy操作SQL Server的中文问题</title><link>http://0x3f.org/posts/chinese-problem-of-sqlalchemy-with-sqlserver/</link><pubDate>Wed, 24 Feb 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/chinese-problem-of-sqlalchemy-with-sqlserver/</guid><description>&lt;p&gt;最初将脚本的文件编码和coding行都设定为UTF-8，在windows下执行时，中文无法保存，报编码错误。将上述两个编码改为GBK后，保存正常，但查询时报错。&lt;/p&gt;
&lt;p&gt;Traceback内容如下：&lt;/p&gt;
```
Traceback (most recent call last):
File "test.py", line 36, in &lt;code&gt;&amp;lt;module&amp;gt;&lt;/code&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for obj in session.query(User):
File "C:\Python26\lib\site-packages\sqlalchemy-0.6beta1-py2.6.egg\sqlalchemy\orm\query.py", line 1411, in instances
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rows = [process[0](row, None) for row in fetch]
File "C:\Python26\lib\site-packages\sqlalchemy-0.6beta1-py2.6.egg\sqlalchemy\orm\mapper.py", line 1788, in _instance
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;populate_state(state, dict_, row, isnew, only_load_props)
File "C:\Python26\lib\site-packages\sqlalchemy-0.6beta1-py2.6.egg\sqlalchemy\orm\mapper.py", line 1677, in populate_state
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;populator(state, dict_, row, isnew=isnew, **flags)
File "C:\Python26\lib\site-packages\sqlalchemy-0.6beta1-py2.6.egg\sqlalchemy\orm\strategies.py", line 118, in new_execute
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dict_[key] = row[col]
File "C:\Python26\lib\site-packages\sqlalchemy-0.6beta1-py2.6.egg\sqlalchemy\engine\base.py", line 1634, in __getitem__
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return self.__colfuncs[key][0](self.__row)
File "C:\Python26\lib\site-packages\sqlalchemy-0.6beta1-py2.6.egg\sqlalchemy\engine\base.py", line 1716, in getcol
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return processor(row[index])
File "C:\Python26\lib\site-packages\sqlalchemy-0.6beta1-py2.6.egg\sqlalchemy\types.py", line 568, in process
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return decoder(value)[0]
File "C:\Python26\lib\encodings\utf_8.py", line 16, in decode
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)&lt;/p&gt;</description></item><item><title>被迫弃UMS而用KMS</title><link>http://0x3f.org/posts/switching-from-ums-to-kms/</link><pubDate>Sat, 13 Feb 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/switching-from-ums-to-kms/</guid><description>&lt;p&gt;昨天更新了一下系统，今天开机就白屏了。于是先关掉Compiz，看了一下Archlinux的&lt;a href="http://www.archlinux.org/news/484/"&gt;新闻&lt;/a&gt;，发现新的&lt;strong&gt;xf86-video-intel&lt;/strong&gt;中已经移除了UMS，也就意味着只能使用KMS做3D加速了。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.thinkwiki.org/wiki/Intel_Graphics_Media_Accelerator_950#User_mode_setting_.28UMS.29"&gt;UMS&lt;/a&gt;的全称是&lt;strong&gt;User Mode-Setting&lt;/strong&gt;，是一种传统的图形界面初始化方案，即在X加载之后由它初始化图形界面。这种方案的弊端是虚拟终端不具备显示和处理图形的能力，同时虚拟终端和图形界面之间的切换显得缓慢并带有闪烁。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://wiki.archlinux.org/index.php/KMS"&gt;KMS&lt;/a&gt;的全称是&lt;strong&gt;Kernel Mode-Setting&lt;/strong&gt;，是新一代图形界面初始化方案，它将图形界面的初始化由X加载之后由X负责进行改为在内核初始化时由内核进行。KMS的好处不仅仅是解决了上面UMS的问题，同时也使得Linux具备了在启动时显示漂亮的开机图示的能力。另外，在3D加速性能和低功耗方面，KMS也较UMS更胜一筹。&lt;/p&gt;
&lt;p&gt;我的&lt;a href="http://0x3f.org/?p=819"&gt;Thinkpad X200&lt;/a&gt;使用的是Intel GMA 945的芯片组，而Archlinux的&lt;a href="http://wiki.archlinux.org/index.php/Intel_(简体中文)#KMS_.28Kernel_Mode_Setting.29"&gt;Wiki&lt;/a&gt;上仍以915为例，所以尝试着做如下内容：&lt;/p&gt;
&lt;p&gt;一、去除/boot/grub/menu.lst中Kernel启动参数中的&lt;a href="http://0x3f.org/?p=866"&gt;vga参数&lt;/a&gt;；&lt;/p&gt;
&lt;p&gt;二、加入以下内容到/etc/modprobe.d/modprobe.conf：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;options i945 modeset=1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;三、在/etc/rc.conf中的&lt;strong&gt;MODULES&lt;/strong&gt;行加入&lt;strong&gt;intel_agp&lt;/strong&gt;和&lt;strong&gt;i945&lt;/strong&gt;；&lt;/p&gt;
&lt;p&gt;重启系统后，Compiz白屏问题解决，3D加速性能似乎有所上升。&lt;/p&gt;</description></item><item><title>PHP后台echo过多会导致进程崩溃</title><link>http://0x3f.org/posts/too-many-echoes-may-crash-php/</link><pubDate>Sun, 31 Jan 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/too-many-echoes-may-crash-php/</guid><description>&lt;p&gt;这是去年晚些时侯发现的一个问题。&lt;/p&gt;
&lt;p&gt;公司产品的后台定时任务应该是用独立的PHP进程驱动的。在做一个项目的时候，为了便于手工调试，我在定时任务中使用了大量的echo输出信息并在浏览器中手工执行此任务的脚本。&lt;/p&gt;
&lt;p&gt;手工执行通过，输出信息完全没有问题。但在实际运行的过程中，一个很诡异的事情发生了：即使我将实际处理数据的代码全部注释掉，只对原始数据做简单的查询，此定时任务仍然极其健壮地中途退出。最要命的是无论程序日志还是PHP的错误日志，都没有任何相关信息。直到后来我把所有echo输出都取消，问题才解决。&lt;/p&gt;
&lt;p&gt;事后模糊地记得很久以前似乎在哪本书上看到过在无输出设备的情况下echo过多数据会导致PHP进程崩溃的内容，但原因已想不起来了。&lt;/p&gt;</description></item><item><title>VirtualBox的Host Interface网络接入方式的配置</title><link>http://0x3f.org/posts/virtualbox-host-interface/</link><pubDate>Sun, 31 Jan 2010 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/virtualbox-host-interface/</guid><description>&lt;p&gt;&lt;a href="http://zh.wikipedia.org/wiki/VirtualBox"&gt;VirtualBox&lt;/a&gt;安装后默认的网络接入方式是&lt;a href="http://zh.wikipedia.org/wiki/%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%8D%A2"&gt;NAT&lt;/a&gt;，也是最简单的一种。但NAT网络中的虚拟机系统不具有和主机同一网段的IP地址，不能和主机直接通信。这对于开发者来说是不适用的。&lt;/p&gt;
&lt;p&gt;Host Interface网络接入方式可以使虚拟机系统获得与主机同一网段的IP地址，因此也使得虚拟机系统像主机所在的局域网中的一台真实的计算机一样，可以和其它计算机通信。&lt;/p&gt;
&lt;p&gt;对于Linux平台的VirtualBox，可以有两种方式实现Host Interface网络。一是使用系统网桥，二是使用VirtualBox内建的机制。&lt;/p&gt;
&lt;p&gt;第一种方式复杂但通用，尤其是对于2.1.0以前的版本来说，这是唯一的途径。从2.1.0开始，VirtuaBox内建了支持Host Interface的机制，这极大地简化了此类型网络的配置。&lt;/p&gt;
&lt;p&gt;首先，加载&lt;strong&gt;vboxnetflt&lt;/strong&gt;模块：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;sudo modprobe vboxnetflt&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后在VirtualBox中配置虚拟机的网络连接方式，选择“&lt;strong&gt;Bridged Adapter&lt;/strong&gt;”。&lt;/p&gt;
&lt;p&gt;最后启动虚拟机即可。&lt;/p&gt;
&lt;p&gt;另外，若虚拟机系统是精简版的Windows，网卡驱动可能不会自动安装，这时需要另外下载网卡的驱动并安装。&lt;/p&gt;
&lt;p&gt;为方便起见，可将vboxnetflt模块加入到开机自动启动的模块列表中，每种发行版设置自启动模块的位置和方法不一样，在Archlinux下，是在&lt;strong&gt;/etc/rc.conf&lt;/strong&gt;文件中的&lt;strong&gt;modules&lt;/strong&gt;行中设置。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;参考文章：&lt;a href="http://wiki.archlinux.org/index.php/VirtualBox"&gt;Archlinux Wiki: VirtualBox&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description></item><item><title>立方体归来</title><link>http://0x3f.org/posts/cube-is-back/</link><pubDate>Tue, 24 Nov 2009 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/cube-is-back/</guid><description>上次鼓捣出立方体还是几年前在学校的时候，&lt;a href="http://zh.wikipedia.org/zh-cn/Ubuntu"&gt;Ubuntu&lt;/a&gt;+&lt;a href="http://en.wikipedia.org/wiki/Beryl_(window_manager)"&gt;Beryl&lt;/a&gt;。
我那个时候的台式机，&lt;a href="http://en.wikipedia.org/wiki/Celeron#Tualatin-256"&gt;Celeron Tualatin&lt;/a&gt;+256M SDRAM+GForce 440，跑XP要了亲命，忍无可忍而投奔Linux，结果一不小心鼓捣出了立方体，捎带着Firefox、OpenOffice开了一大堆，屁事儿没有，我就是这么死心塌地地上了贼船，直至今天。
后来一直用&lt;a href="http://zh.wikipedia.org/zh-cn/ArchLinux"&gt;Archlinux&lt;/a&gt;，习惯了&lt;a href="http://zh.wikipedia.org/zh-cn/Fluxbox"&gt;Fluxbox&lt;/a&gt;和&lt;a href="http://zh.wikipedia.org/zh-cn/Openbox"&gt;Openbox&lt;/a&gt;的简洁。买了X200后曾试图找寻一下旧日华丽的记忆，但却人是物非，新的X200、新的Archlinux、新的&lt;a href="http://zh.wikipedia.org/zh-cn/Compiz_Fusion"&gt;Compiz-fusion&lt;/a&gt;远不如当年的老牛破车那么搭调。虽说也搞出了立方体，但所有的窗口都没有边框，于是作罢。
上周六鬼使神差的进入GNOME并打开Fusion-icon，奇迹就这么出现了：
&lt;a href="http://picasaweb.google.com/lh/photo/HkPacmXQACapxzViLh4kRw?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/SwvnvUJImNI/AAAAAAAABPk/076ZiKsl4Uw/s400/screenshot_001.png" /&gt;&lt;/a&gt;</description></item><item><title>Windows下GVim的全屏</title><link>http://0x3f.org/posts/fullscreen-for-gvim-on-windows/</link><pubDate>Thu, 17 Sep 2009 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/fullscreen-for-gvim-on-windows/</guid><description>下载gvim的一个扩展“&lt;a href="https://github.com/derek/gvimfullscreen_win32"&gt;gvimfullscreen_win32&lt;/a&gt;”，并解压缩。
将&lt;strong&gt;gvimfullscreen.dll&lt;/strong&gt;复制到gvim安装目录下，与&lt;strong&gt;gvim.exe&lt;/strong&gt;同目录。
修改gvim配置文件&lt;strong&gt;_vimrc&lt;/strong&gt;，在其中添加如下内容：
```vim
if has('win32')
map &lt;F11&gt; &lt;Esc&gt;:call libcallnr("gvimfullscreen.dll", "ToggleFullScreen", 0)&lt;CR&gt;
endif
```
此后，即可使用&lt;strong&gt;F11&lt;/strong&gt;键开关gvim的全屏状态。</description></item><item><title>欧拉工程第十一解</title><link>http://0x3f.org/posts/project-euler-11/</link><pubDate>Tue, 12 May 2009 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-11/</guid><description>&lt;blockquote&gt;
&lt;p&gt;In the 20×20 grid below, four numbers along a diagonal line have been marked in red.&lt;/p&gt;
&lt;p&gt;08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48&lt;/p&gt;</description></item><item><title>rxvt-unicode的真透明</title><link>http://0x3f.org/posts/true-transparent-of-rxvt-unicode/</link><pubDate>Sat, 28 Feb 2009 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/true-transparent-of-rxvt-unicode/</guid><description>&lt;div class="illustration_right"&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/J2FyvgBhXopEgPlX9whJ3w?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/Saghr1cRaoI/AAAAAAAAA0o/fye5JZl3Pxc/s288/2009-02-28-012206_1280x800_scrot.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;nacre同学说，urxvt是可以实现真透明的。起初我以为是要用&lt;a href="http://www.forchheimer.se/transset-df/"&gt;transset-df&lt;/a&gt;来实现，但这个东西一般需要手动操作，不具有太大的实用性，而且会把整个窗口透明化。不过后来发现真的不需要用它来画蛇添足，有&lt;a href="http://wiki.archlinux.org/index.php/Xcompmgr"&gt;xcompmgr&lt;/a&gt;足矣。&lt;/p&gt;
&lt;p&gt;因为我用&lt;a href="http://en.wikipedia.org/wiki/Openbox"&gt;openbox&lt;/a&gt;，要实现窗口的阴影和动画效果，xcompmgr是必须的，我把它设成了开机自启动。比起xcompmgr默认的参数值，下面这条定制的命令实现了简洁的阴影和合理的渐隐渐显时间，因此提供了一个各方面都比较均衡、合理的桌面体验：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;xcompmgr -Ss -n -Cc -fF -I-10 -O-10 -D1 -t-3 -l-4 -r4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后在.Xresources中添加以下两行：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;URxvt.depth:32
URxvt.background:rgba:0000/0000/0000/dddd&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最后当然要执行一下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;xrdb ~/.Xresources&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;此后直接启动urxvt即可。&lt;/p&gt;
&lt;p&gt;这里面最有意思的就是background项的配置，它有两种形式，一种是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;URxvt.background:[80]black&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;还有一种就是前面提到的形式。&lt;/p&gt;
&lt;p&gt;第一种形式中，中括号里的数字表示半透明度对应的百分比，括号外是颜色名称；第二种形式提供了比第一种更多的色彩选择，四组数字都是十六进制数，前三组是RGB颜色值，最后一组是半透明度，数值越大，透明度越低。&lt;/p&gt;
&lt;p&gt;在查阅“man urxvt”的时候，发现urxvt的man pages里的内容真是异常丰富，大部分功能都讲解得言简意赅。以往还抱怨这个东西在网上连个健全的文档都找不到，原来全在这儿呢，真不知道以往无数次地man的时候为什么没有注意到这些，难道man了rxvt了？&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PS：这样实现urxvt的真半透明后，貌似xcompmgr实现的阴影在urxvt身上就消失了，求解中……&lt;/em&gt;&lt;/p&gt;</description></item><item><title>完美的终端模拟器：rxvt-unicode</title><link>http://0x3f.org/posts/rxvt-unicode-256color-is-perfect/</link><pubDate>Sun, 08 Feb 2009 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/rxvt-unicode-256color-is-perfect/</guid><description>&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Rxvt-unicode"&gt;urxvt&lt;/a&gt;（&lt;a href="http://www.rxvt.org/"&gt;rxvt&lt;/a&gt;的unicode版本，支持多国语言，&lt;a href="http://software.schmorp.de/pkg/rxvt-unicode.html"&gt;官方网站&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;具有以下特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持真半透明&lt;/li&gt;
&lt;li&gt;支持Unicode编码，支持多国语言&lt;/li&gt;
&lt;li&gt;支持英文和非英文字符使用不同的字体&lt;/li&gt;
&lt;li&gt;支持CS模式，节省系统资源&lt;/li&gt;
&lt;li&gt;轻量，速度快&lt;/li&gt;
&lt;li&gt;支持Perl扩展功能&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但是urxvt有一个很影响情绪的缺陷，就是字符的间距过大，看起来很不舒服。不过已有补丁用来解决这个问题，例如Archlinux用户可以安装&lt;a href="http://aur.archlinux.org/packages.php?ID=32488"&gt;rxvt-unicode-chinese&lt;/a&gt;：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/6B48rqC08p3C7paP_Y651w?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_ceUJ_lBTHzc/SY71tgK4J0I/AAAAAAAAAw4/3Vf4HbPZfS4/s400/rxvt-unicode-256color.png" /&gt;&lt;/a&gt;&lt;/p&gt;
urxvt的配置选项可以参考其官方网站上的说明，另外&lt;a href="http://pastebin.com/WzT6pTKA"&gt;这里&lt;/a&gt;有一份详细的配置文件。
&lt;strong&gt;更新日志：&lt;/strong&gt;
&lt;strong&gt;2011-01-15&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;修改文章标题&lt;/li&gt;
&lt;li&gt;重写文章内容&lt;/li&gt;
&lt;li&gt;由于原来的rxvt-unicode-256color包已不存在，更换为rxvt-unicode-chinese&lt;/li&gt;
&lt;li&gt;补充一份配置文件&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>欧拉工程第十解</title><link>http://0x3f.org/posts/project-euler-10/</link><pubDate>Tue, 18 Nov 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-10/</guid><description>&lt;blockquote&gt;&lt;p&gt;The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.&lt;/p&gt;
&lt;p&gt;Find the sum of all the primes below two million.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;题目越来越变态，开始好玩儿了。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://0x3f.org/?p=753"&gt;第七解&lt;/a&gt;里的算法在这里算是废了，一万个素数都算得那么费劲，两百万以下的素数有十几万个，不得不用筛选法了。&lt;/p&gt;
&lt;p&gt;普通的筛选效率也不行，当初就是因为这个原因才没用它。不过优化过的筛选法就很奇妙了，下面是Lua的实现：&lt;/p&gt;
&lt;p&gt;
```lua
require('math')
local limit = 2000000
local primes = {}
for i=1,limit do
table.insert(primes,true)
end
primes[0] = false
primes[1] = false
for i=0,math.floor(math.sqrt(limit)) do
if primes[i] then
for j=math.pow(i,2),limit,i do
primes[j] = false
end
end
end
local sumVal = 0
for i,j in ipairs(primes) do
if j then
sumVal = sumVal + i
end
end
print(sumVal)
```
&lt;/p&gt;</description></item><item><title>欧拉工程第九解</title><link>http://0x3f.org/posts/project-euler-9/</link><pubDate>Mon, 10 Nov 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-9/</guid><description>&lt;blockquote&gt;
&lt;p&gt;A Pythagorean triplet is a set of three natural numbers, &lt;b&gt;&lt;em&gt;a&lt;/em&gt;&lt;/b&gt; &lt; &lt;b&gt;&lt;em&gt;b&lt;/em&gt;&lt;/b&gt; &lt; &lt;b&gt;&lt;em&gt;c&lt;/em&gt;&lt;/b&gt;, for which,&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;em&gt;a&lt;/em&gt;&lt;/b&gt;&lt;sup&gt;2&lt;/sup&gt; + &lt;b&gt;&lt;em&gt;b&lt;/em&gt;&lt;/b&gt;&lt;sup&gt;2&lt;/sup&gt; = &lt;b&gt;&lt;em&gt;c&lt;/em&gt;&lt;/b&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;For example, 3&lt;sup&gt;2&lt;/sup&gt; + 4&lt;sup&gt;2&lt;/sup&gt; = 9 + 16 = 25 = 5&lt;sup&gt;2&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;There exists exactly one Pythagorean triplet for which &lt;b&gt;&lt;em&gt;a&lt;/em&gt;&lt;/b&gt; + &lt;b&gt;&lt;em&gt;b&lt;/em&gt;&lt;/b&gt; + &lt;b&gt;&lt;em&gt;c&lt;/em&gt;&lt;/b&gt; = 1000.
Find the product &lt;b&gt;&lt;em&gt;abc&lt;/em&gt;&lt;/b&gt;.
&lt;/blockquote&gt;
&lt;p&gt;解：&lt;/p&gt;
&lt;p&gt;
```python
flag = False
for a in range(1,1000):
for b in range(1,1000):
if a ** 2 + b ** 2 == (1000 - a - b) ** 2:
print a,b,(1000 - a - b)
print a * b * (1000 - a - b)
flag = True
break
if flag:
break
```
&lt;/p&gt;</description></item><item><title>欧拉工程第八解</title><link>http://0x3f.org/posts/project-euler-8/</link><pubDate>Sun, 09 Nov 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-8/</guid><description>&lt;blockquote&gt;&lt;p&gt;Find the greatest product of five consecutive digits in the 1000-digit number.&lt;/p&gt;
&lt;p&gt;73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;穷举，解：&lt;/p&gt;
&lt;p&gt;
```python
def MakeProduct(strNum):
prod = 1
for char in strNum:
prod = prod * int(char)
return prod
def GetTheFirstProduct(strNum):
if len(strNum) &lt; 5:
return 0,0
return MakeProduct(strNum[:5]),strNum[1:]
num = '7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'
largestProduct = 0
while len(num) &gt;= 5:
tmp = GetTheFirstProduct(num)
if tmp == (0,0):
break
num = tmp[1]
if largestProduct &lt; tmp[0]:
largestProduct = tmp[0]
print largestProduct
```
&lt;/p&gt;</description></item><item><title>欧拉工程第七解</title><link>http://0x3f.org/posts/project-euler-7/</link><pubDate>Fri, 31 Oct 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-7/</guid><description>&lt;p&gt;第七解：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.&lt;/p&gt;
&lt;p&gt;What is the 10001st prime number?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;穷举，并加以最大程度的优化：对大于2的素数，只判断奇数；判断一个奇数是否素数时，只拿已经找到的素数中小于第这个数平方根的数来相除，如果均不能整除，就是素数。Python的实现：&lt;/p&gt;
&lt;p&gt;
```python
def IsPrimeNum(num,feed):
from math import sqrt
tmp = feed[:]
while tmp[-1] &gt; int(sqrt(num)):
tmp.pop()
for i in tmp:
if num % i == 0:
return False
return True
limit = 10001
feed = [2,3,5,7]
temp = 7
counter = 4
while counter &lt; limit :
temp += 2
if IsPrimeNum(temp,feed):
feed.append(temp)
counter += 1
print temp
```
&lt;/p&gt;</description></item><item><title>欧拉工程第六解</title><link>http://0x3f.org/posts/project-euler-6/</link><pubDate>Wed, 29 Oct 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-6/</guid><description>&lt;p&gt;第六解：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The sum of the squares of the first ten natural numbers is,
12 + 22 + &amp;hellip; + 102 = 385&lt;/p&gt;
&lt;p&gt;The square of the sum of the first ten natural numbers is,
(1 + 2 + &amp;hellip; + 10)2 = 552 = 3025&lt;/p&gt;
&lt;p&gt;Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 385 = 2640.
Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.&lt;/p&gt;</description></item><item><title>欧拉工程第五解</title><link>http://0x3f.org/posts/project-euler-5/</link><pubDate>Mon, 27 Oct 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-5/</guid><description>&lt;p&gt;第五解：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest number that is evenly divisible by all of the numbers from 1 to 20?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;解：&lt;/p&gt;
&lt;p&gt;
```python
#为简洁明了，此处不作校验
def GetGreatestCommonDivisor(min,max):
'''辗转相除法求最大公约数'''
while min &gt; 0:
tmp = min
min = max % min
max = tmp
return max
def GetLeastCommonMultiple(a,b):
if a &gt; b:
max = a
min = b
else:
max = b
min = a
div = GetGreatestCommonDivisor(min,max)
return min * max / div
temp = 1
for i in range(1,21):
temp = GetLeastCommonMultiple(i,temp)
print temp
```
&lt;/p&gt;</description></item><item><title>欧拉工程第四解</title><link>http://0x3f.org/posts/project-euler-4/</link><pubDate>Wed, 22 Oct 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-4/</guid><description>&lt;p&gt;第四解：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;解：&lt;/p&gt;
&lt;p&gt;
```python
largestPalindrome = 0
for i in range(100,1000):
for j in range(100,1000):
product = i * j
if int(str(product)[::-1]) == product and product &gt; largestPalindrome:
largestPalindrome = product
print largestPalindrome
```
&lt;/p&gt;</description></item><item><title>欧拉工程第三解</title><link>http://0x3f.org/posts/project-euler-3/</link><pubDate>Tue, 21 Oct 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-3/</guid><description>&lt;p&gt;第三解：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;解：&lt;/p&gt;
&lt;p&gt;
```python
feed = 600851475143
def GetFactor(feed,footmark):
while footmark &lt; feed:
footmark += 2
if feed % footmark == 0:
print footmark
GetFactor(feed / footmark,footmark)
break
GetFactor(feed,1)
```
&lt;/p&gt;
&lt;p&gt;&lt;a href="http://picasaweb.google.com/lh/photo/CQ25Wrocadk-dyd7sOiRUA"&gt;&lt;img src="http://lh6.ggpht.com/lenin.lee/SP3inG0AczI/AAAAAAAAAjA/DBMygQUR9HI/s400/project_euler_problem_003.png" /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>欧拉工程第二解</title><link>http://0x3f.org/posts/project-euler-2/</link><pubDate>Sun, 19 Oct 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-2/</guid><description>&lt;p&gt;第二解：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, &amp;hellip;
Find the sum of all the even-valued terms in the sequence which do not exceed four million.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;解：&lt;/p&gt;
&lt;p&gt;
```python
i = 1
j = 2
sum = 0
while j &lt; 4000000 :
if j % 2 == 0 :
sum = sum + j
t = i
i = j
j = t + j
print sum
```
&lt;/p&gt;</description></item><item><title>欧拉工程第一解</title><link>http://0x3f.org/posts/project-euler-1/</link><pubDate>Mon, 06 Oct 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/project-euler-1/</guid><description>&lt;div style="float:right;margin-left:10px;margin-bottom:10px;"&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/AAMfMJges97jrmxxYmmsXw"&gt;&lt;img src="http://lh5.ggpht.com/lenin.lee/SOjhkJQQ7HI/AAAAAAAAAbk/HT6_ZIxVCJE/s144/euler.jpg" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;
“&lt;a href="http://projecteuler.net/"&gt;欧拉工程&lt;/a&gt;”是一个很有意思的网站，它每周会提供一道数学题，要求访问者使用任一种编程语言设计一个计算机程序求解。到现在为止已经出了二百一十一道题，当然，题的难度是依次递增的。几十个国家的程序员已参与了这个工程，截至目前，中国有四百多人参与，但是解决所有的二百多道题的只有一个人。
&lt;/p&gt;
&lt;p&gt;
我觉得没事儿的时候做一道很有意思，下面是第一道，很简单：
&lt;/p&gt;
&lt;blockquote&gt;
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
&lt;/blockquote&gt;
&lt;p&gt;
最容易想到的一算法就是依次取出一到一千的整数，只要是三或五的倍数，就累加起来，最终的和就是结果：
&lt;/p&gt;
```python
sum = 0
for num in range(1,1000):
if not (num % 3 != 0 and num % 5 != 0):
sum += num
print sum
```
&lt;p&gt;
但是我觉得这个算法太普通了，从一到一千要做一千次循环，时间复杂度会比较高。所以我设想只取出三和五的倍数，然后相加就行了，所需要考虑的只是怎么处理三和五的公倍数的问题。下面是我的算法，只有三百多次循环：
&lt;/p&gt;</description></item><item><title>为rxvt-unicode开启标签和链接支持</title><link>http://0x3f.org/posts/let-rxvt-unicode-support-tags-and-links/</link><pubDate>Thu, 20 Mar 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/let-rxvt-unicode-support-tags-and-links/</guid><description>&lt;p&gt;写完&lt;a href="http://0x3f.org/?p=376"&gt;urxvt-unicode快速上手&lt;/a&gt;，本以为已将urxvt的用法一网打尽，不料AndyWxy网友又找到了两个新的功能：使urxvt启用标签和在urxvt中打开网页链接。&lt;/p&gt;
&lt;p&gt;标签功能很实用，一般为了达到复用终端窗口的目的会采用两种方式：一是配合screen使用，另一个就是启用标签。然而前者有一个缺点就是不直观，标签页恰好能弥补这个缺陷。urxvt不愧是个功能强大的终端工具，如果在编译时开启perl支持，则urxvt可启用多标签功能。用法如下：&lt;/p&gt;
&lt;p&gt;一是在启动的时候加入命令行参数：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;urxvt -pe tabbed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;二是在配置文件“.Xresources”中添加如下配置信息：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;URxvt.perl-ext-common: default,tabbed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;则默认情况下执行urxvt就会打开多标签功能。urxvt的标签支持使用鼠标操作，同时可以使用Ctrl+Shift+左右箭头来切换标签页，使用Ctrl+Shift+向下箭头开启新标签。&lt;/p&gt;
&lt;p&gt;另外一个功能就是可以通过在urxvt中的链接上点击鼠标左键来通过设定的浏览器打开之。首先在“.Xresources”文件中添加如下内容：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;URxvt.urlLauncher: firefox
URxvt.matcher.button: 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后使用如下命令打开urxvt：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;urxvt -pe matcher&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;即可。也可以在配置文件中添加上述内容之后再添加一行：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;URxvt.perl-ext-common: matcher&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;此后即默认开启在终端窗口中打开链接的功能。注意修改“.Xresources”文件后需要执行如下命令才能使修改后的配置文件生效：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;xrdb ~/.Xresources&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>rxvt-unicode快速上手</title><link>http://0x3f.org/posts/quick-guide-for-rxvt-unicode/</link><pubDate>Fri, 07 Mar 2008 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/quick-guide-for-rxvt-unicode/</guid><description>&lt;!--rxvt-unicode快速上手--&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href="http://www.rxvt.org/"&gt;rxvt&lt;/a&gt;是我最喜欢的虚拟终端，它有以下优点：
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;轻量&lt;/b&gt;：体积小，启动速度快，占用系统资源极低&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;美观&lt;/b&gt;：各种外观（如颜色、字体、半透明等）均可定制&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;功能强&lt;/b&gt;：具备一个终端工具应当有的各种实用功能
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;然而它很难被初学者接受，一是因为它的缺省外观很难看，而自身又不提供图形界面的配置工具，只能通过修改配置文件来设置，然而网上相关的资料却非常少；二是因为在rxvt中使用复制和粘贴非常“不方便”，它并不支持人们已经习惯的Ctrl+C和Ctrl+V的复制、粘贴方式，这也是网上关于rxvt问得最多的问题；最后一个门槛是它对中文等东亚文字的支持不好。
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;其实rxvt以上三个所谓的门槛都是初学者对它的误解。首先rxvt的配置文件非常简单，只要学过英语的人都能看明白，通过简单的配置就可以使之变得非常漂亮，丝毫不逊色于&lt;a href="http://en.wikipedia.org/wiki/Konsole"&gt;Konsole&lt;/a&gt;、&lt;a href="http://en.wikipedia.org/wiki/GNOME_Terminal"&gt;Gnome-terminal&lt;/a&gt;等主流终端。
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;其次，rxvt虽然不支持Ctrl+C和Ctrl+V的复制、粘贴，但是它有自己的一套操作方式。Linux下普遍使用的图形界面均为&lt;a href="http://www.x.org/"&gt;X11&lt;/a&gt;，而X11支持一种独特的复制粘贴方式，即如果你在另一个程序比如文本编辑器中使用鼠标拖动来高亮一段文字后，不用进行任何操作，此时选中的内容已经复制到剪贴板中了，随后在rxvt中单击鼠标中键即可将选中内容粘贴到其中，此外，如果鼠标没有中键，可以同时按下左右键以达到同样的效果，还可以使用Shift+Insert组合键来完成粘贴；反之，从rxvt中向外复制内容同样如此。
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最后，虽然rxvt对东亚文字支持不好，但是rxvt有几个修改版，其中一个就是&lt;a href="http://software.schmorp.de/pkg/rxvt-unicode.html"&gt;rxvt-unicode&lt;/a&gt;。顾名思义，rxvt-unicode支持unicode编码，因此对东亚文字的支持完全没有问题。安装完成后，使用urxvt即可打开之。
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;此外，rxvt-unicode还有一个很好的特性，它可以工作在C/S模式。使用urxvtd启动rxvt的后台程序，此后任何时候使用urxvtc即可打开一个rxvt终端，所有的rxvtc共用一个urxvtd，因此在同时运行的终端比较多的时候，在内存占用上要比全部使用urxvt少一些。不过据我粗略计算，如果打开的终端不是非常多（比如说几十个），那么使用普通模式和使用C/S模式对内存的占用没有太大的差距，因为普通模式下的urxvt占用内存本身就非常少。在我看来使用C/S模式的最大好处是启动速度比普通模式要快一些。
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;关于rxvt的美化和设置，可以参看我以前写的一篇&lt;a href="http://0x3f.org/?p=316"&gt;文章&lt;/a&gt;。下图是我现在使用的rxvt的截图：
&lt;/p&gt;&lt;p&gt;
&lt;a href="http://picasaweb.google.com/lenin.lee/Weblog/photo#5173912470992319602"&gt;&lt;img src="http://lh5.google.com/lenin.lee/R81t-tR19HI/AAAAAAAAASc/DNDprQnOY-A/s400/urxvt.png" /&gt;&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;以下是我当前的rxvt配置文件的内容：
&lt;/p&gt;&lt;p&gt;
&lt;blockquote&gt;
!Xft.dpi:96
!fontforge.FontView.FontFamily:wenquanyi bitmap song
Rxvt.geometry:192×144
Rxvt.background:#2e2e2e
Rxvt.foreground:antiquewhite
Rxvt.colorBD:yellow
Rxvt.colorUL:green
Rxvt.multichar_encoding:utf-8
Rxvt.scrollBar:Fault
Rxvt.scrollBar_right:True
Rxvt.scrollBar_floating: True
Rxvt.scrollstyle: next
Rxvt.saveLines:10000
Rxvt.color0:black
Rxvt.color1:red3
Rxvt.color2:springgreen
Rxvt.color3:wheat3
Rxvt.color4:navy
Rxvt.color5:magenta4
Rxvt.color6:steelblue1
Rxvt.color7:gray85
Rxvt.color8:gray10
Rxvt.color9:SkyBlue3
Rxvt.color10:chartreuse3
Rxvt.color11:lightgoldenrod2
Rxvt.color12:SkyBlue1
Rxvt.color13:pink1
Rxvt.color14:lightblue1
Rxvt.color15:#dbeff9
Rxvt.font:xft:Vera Sans YuanTi Mono :size=10,xft:Monospace:size=10
Rxvt.menu:/etc/X11/rxvt.menu
Rxvt.preeditType:Root
Rxvt.transparency:255
&lt;/blockquote&gt;
&lt;/p&gt;</description></item><item><title>rxvt-unicode的半透明方案</title><link>http://0x3f.org/posts/half-transparent-for-rxvt-unicode/</link><pubDate>Tue, 16 Oct 2007 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/half-transparent-for-rxvt-unicode/</guid><description>&lt;!-- urxvt的半透明方案 --&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rxvt是个快速且节省内存的模拟终端，原版rxvt对中文等非字母语言的支持不好，所以它有许多修改版，rxvt-unicode-ml是比较适合中国人使用的rxvt修改版。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rxvt轻量但不简单，它有许多设置选项和启动参数，用户可以在命令行使用“&lt;font color="#036803"&gt;rxvt -help&lt;/font&gt;”查看其常用启动参数，使用“&lt;font color="#036803"&gt;rxvt --help&lt;/font&gt;”查看更为详细的启动参数。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;通过修改用户主目录下的“&lt;font color="#a73800"&gt;.Xresources&lt;/font&gt;”文件可以配置urxvt的行为，从而不必每次都加启动参数，我的"&lt;font color="#a73800"&gt;.Xresources&lt;/font&gt;"文件内容如下：&lt;/p&gt;
&lt;blockquote&gt;&lt;font color="#036803"&gt;Rxvt.background:white&lt;br&gt;
Rxvt.foreground:black&lt;br&gt;
Rxvt.colorBD:yellow&lt;br&gt;
Rxvt.colorUL:green&lt;br&gt;
Rxvt.multichar_encoding:gb2312&lt;br&gt;
Rxvt.scrollBar:Fault&lt;br&gt;
Rxvt.scrollBar_right:True&lt;br&gt;
Rxvt.scrollBar_floating: True&lt;br&gt;
Rxvt.scrollstyle: next&lt;br&gt;
Rxvt.saveLines:10000&lt;br&gt;
Rxvt.color0:black&lt;br&gt;
Rxvt.color1:red3&lt;br&gt;
Rxvt.color2:springgreen&lt;br&gt;
Rxvt.color3:wheat3&lt;br&gt;
Rxvt.color4:navy&lt;br&gt;
Rxvt.color5:magenta4&lt;br&gt;
Rxvt.color6:steelblue1&lt;br&gt;
Rxvt.color7:gray85&lt;br&gt;
Rxvt.color8:gray10&lt;br&gt;
Rxvt.color9:SkyBlue3&lt;br&gt;
Rxvt.color10:chartreuse3&lt;br&gt;
Rxvt.color11:lightgoldenrod2&lt;br&gt;
Rxvt.color12:SkyBlue1&lt;br&gt;
Rxvt.color13:pink1&lt;br&gt;
Rxvt.color14:lightblue1&lt;br&gt;
Rxvt.color15:#dbeff9&lt;br&gt;
Rxvt.font:xft:Vera Sans YuanTi Mono :size=10,xft:Monospace:size=10&lt;br&gt;
Rxvt.menu:/etc/X11/rxvt.menu&lt;br&gt;
Rxvt.preeditType:Root&lt;br&gt;
Rxvt.geometry:192×174&lt;br&gt;
Rxvt.transparency:255&lt;/font&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这个配置文件是白底黑字，当然可以修改为全透明或者半透明，不过，只要在启动时加入启动参数就可以实现全透明：&lt;/p&gt;
&lt;blockquote&gt;&lt;font color="#036803"&gt;urxvt -tr&lt;/font&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;也可以实现半透明：&lt;/p&gt;
&lt;blockquote&gt;&lt;font color="#036803"&gt;urxvt -fg lightgray -bg black -bc -tr -tint lightgray -sh 60 -sr&lt;/font&gt;&lt;/blockquote&gt;</description></item><item><title>UBUNTU 6.10 Edgy Eft 入门全程导用</title><link>http://0x3f.org/posts/ubuntu-610-tutorial/</link><pubDate>Sun, 08 Apr 2007 00:00:00 +0000</pubDate><guid>http://0x3f.org/posts/ubuntu-610-tutorial/</guid><description>&lt;p&gt;&lt;a HREF="http://forum.ubuntu.org.cn/viewtopic.php?t=32798&amp;amp;highlight=" TARGET="_blank"&gt;&lt;a href="http://forum.ubuntu.org.cn/viewtopic.php?t=32798&amp;amp;amp;highlight="&gt;http://forum.ubuntu.org.cn/viewtopic.php?t=32798&amp;amp;amp;highlight=&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="目录"&gt;目录&lt;/h2&gt;
&lt;p&gt;一、安装Edgy与硬盘的分区&lt;br&gt;
（1）安装与分区&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;3&lt;br&gt;
（2）多硬盘需要注意的一点&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;3&lt;br&gt;
（3）Linux下硬盘分区的概念&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-4&lt;br&gt;
二、改变账户操作理念&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-4&lt;br&gt;
三、修改源并配置网络&lt;br&gt;
（1）源及其使用方法&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-5&lt;br&gt;
（2）配置ADSL网络&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-6&lt;br&gt;
四、系统的中文化与输入法&lt;br&gt;
（1）系统的中文化&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;6&lt;br&gt;
（2）中文字体的美化&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-6&lt;br&gt;
（3）中文输入法的安装与配置&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;8&lt;br&gt;
（4）主要程序界面的汉化&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;11&lt;br&gt;
（5）Abiword中文乱码的解决办法&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-11&lt;br&gt;
五、多媒体播放器的安装与配置&lt;br&gt;
（1）万能播放器 mplayer&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-12&lt;br&gt;
（2）音频播放器 audacious 及 mp3 文件 tag 乱码的解决&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-12&lt;br&gt;
（3）媒体解码库 gstreamer&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;13&lt;br&gt;
六、网络工具的安装与配置&lt;br&gt;
（1）Opera 的安装与配置及中文输入法问题的解决&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;13&lt;br&gt;
（2）即时通讯程序&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;14&lt;br&gt;
（a）集成即时通讯工具 gaim&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-14&lt;br&gt;
（b）最逼真的 QQ 工具&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;15&lt;br&gt;
（c）功能最强大的 QQ 工具 Eva&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;16&lt;br&gt;
（d）多协议即时通讯工具 Kopete&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-16&lt;br&gt;
（3）新闻阅读&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-16&lt;br&gt;
（4）邮件客户端&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;17&lt;br&gt;
（5）下载工具&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-17&lt;br&gt;
（6）p2p 工具&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-17&lt;br&gt;
七、编辑器、编译环境与词典&lt;br&gt;
（1）编辑器&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;17&lt;br&gt;
（2）编译环境&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-17&lt;br&gt;
（3）词典&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;18&lt;br&gt;
八、NVIDA 显卡驱动与 Beryl 的安装&lt;br&gt;
（1）nvida 显卡驱动的安装&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;18&lt;br&gt;
（2）安装 Beryl&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;20&lt;br&gt;
（3）Splash Screen 的安装&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;22&lt;br&gt;
九、Wine 的安装&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;22&lt;br&gt;
十、虚拟机 Vmware&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;23&lt;br&gt;
十一、磁盘分区的挂载&lt;br&gt;
（1）挂载一个原先存在而没有挂载的分区&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;23&lt;br&gt;
（2）新加入一块还没有分区的全新的硬盘&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;24&lt;br&gt;
十二、游戏&lt;br&gt;
（1）linux 下面的游戏&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-25&lt;br&gt;
（2）win 下的游戏&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;25&lt;br&gt;
十三、一些常用工具&lt;br&gt;
（1）读写 ntfs 分区&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-25&lt;br&gt;
（2）java 日记本&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-26&lt;br&gt;
（3）图片管理 Picasa&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;26&lt;br&gt;
（4）光碟烧录 GnomeBaker&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-26&lt;br&gt;
（5）CHM 阅读器&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;26&lt;br&gt;
（6）数学程序&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;-27&lt;br&gt;
十四、Linux 下程序的安装&lt;br&gt;
（1）deb 软件包的安装&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;27&lt;br&gt;
（2）rpm 软件包的安装&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;27&lt;br&gt;
（3）使用源码进行安装&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;28&lt;br&gt;
（4）绿色软件&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;29&lt;br&gt;
十五、其它 GUI 的安装&lt;br&gt;
（1）KDE&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;29&lt;br&gt;
十六、进阶技巧&lt;br&gt;
（1）关于 Grub 的 FAQ&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;29&lt;br&gt;
（2）桌面图标隐藏、显示设置&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;31&lt;br&gt;
（3）在/var/cache/apt/archives 里面发现大量原来使用 apt-get 下来的 deb 包，太占空间了，能不能删掉？31&lt;br&gt;
（4）gvim 的字体太难看，怎样设置为雅黑?&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;31&lt;br&gt;
（5）为什么键盘上的左右箭头不能用了？&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;31&lt;br&gt;
（6）有些常用命令记不住怎么办?&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;32&lt;br&gt;
（7）快速搜索文件&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash;32&lt;br&gt;
（8）“不打开”音乐播放器预听 mp3&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;33&lt;/p&gt;</description></item><item><title>「熊猫烧香」</title><link>http://0x3f.org/posts/panda-burning-joss-sticks/</link><pubDate>Sat, 17 Feb 2007 18:28:00 +0000</pubDate><guid>http://0x3f.org/posts/panda-burning-joss-sticks/</guid><description>&lt;p&gt;前一段的维金，现在的熊猫烧香，windows上总是不消停。&lt;/p&gt;
&lt;p&gt;当年的冲击波，那是我唯一一次中毒的经历，居然还很兴奋。自从转到Linux，感觉这些都离我越来越远，窃自暗爽。&lt;/p&gt;
&lt;p&gt;说到瑞星和卡巴斯基的撕逼，曾经也为选杀毒软件很头疼，后来幡然醒悟，只是个心理安慰，随便装一个就行了。当然，还是现在在Linux上裸奔更好。&lt;/p&gt;</description></item><item><title>Search</title><link>http://0x3f.org/search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://0x3f.org/search/</guid><description/></item></channel></rss>