<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Middle Earth]]></title>
  
  <link href="http://blog.zhangsen.org/" />
  <updated>2012-07-21T18:01:29+08:00</updated>
  <id>http://blog.zhangsen.org/</id>
  <author>
    <name><![CDATA[jesse]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/zhangsen-blog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="zhangsen-blog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[goagent 安装]]></title>
    <link href="http://blog.zhangsen.org/2012/07/goagent-setup.html" />
    <updated>2012-07-21T17:41:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/07/goagent-setup</id>
    <content type="html">&lt;p&gt;我总是后知后觉，现在才开始折腾 goagent。之前买过 VPN，最近一直用 ssh tunnel。试了 goagnet 才发现真心好用啊。&lt;/p&gt;

&lt;p&gt;但是目前 GAE 貌似大面积被封了，所以 goagent 一开始安装都有问题，根本没法传到服务器上。&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;$ python uploader.zip
&lt;/span&gt;&lt;span class='line'&gt;APPID:zhngsn-p4
&lt;/span&gt;&lt;span class='line'&gt;Application: zhngsn-p4 
&lt;/span&gt;&lt;span class='line'&gt;Host: appengine.google.com
&lt;/span&gt;&lt;span class='line'&gt;INFO - - [Jul 21 17:45:56] Server: appengine.google.com
&lt;/span&gt;&lt;span class='line'&gt;Rolling back the update.
&lt;/span&gt;&lt;span class='line'&gt;Traceback (most recent call last):
&lt;/span&gt;&lt;span class='line'&gt;  File "/usr/lib64/python2.7/runpy.py", line 162, in _run_module_as_main
&lt;/span&gt;&lt;span class='line'&gt;    "__main__", fname, loader, pkg_name)
&lt;/span&gt;&lt;span class='line'&gt;  File "/usr/lib64/python2.7/runpy.py", line 72, in _run_code
&lt;/span&gt;&lt;span class='line'&gt;    exec code in run_globals
&lt;/span&gt;&lt;span class='line'&gt;  File "uploader.zip/__main__.py", line 10, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;span class='line'&gt;    main()
&lt;/span&gt;&lt;span class='line'&gt;[...]
&lt;/span&gt;&lt;span class='line'&gt;  File "uploader.zip/google/appengine/tools/appengine_rpc.py", line 365, in Send
&lt;/span&gt;&lt;span class='line'&gt;  File "/usr/lib64/python2.7/urllib2.py", line 400, in open
&lt;/span&gt;&lt;span class='line'&gt;    response = self._open(req, data)
&lt;/span&gt;&lt;span class='line'&gt;  File "/usr/lib64/python2.7/urllib2.py", line 418, in _open
&lt;/span&gt;&lt;span class='line'&gt;    '_open', req)
&lt;/span&gt;&lt;span class='line'&gt;  File "/usr/lib64/python2.7/urllib2.py", line 378, in _call_chain
&lt;/span&gt;&lt;span class='line'&gt;    result = func(*args)
&lt;/span&gt;&lt;span class='line'&gt;  File "/usr/lib64/python2.7/urllib2.py", line 1215, in https_open
&lt;/span&gt;&lt;span class='line'&gt;    return self.do_open(httplib.HTTPSConnection, req)
&lt;/span&gt;&lt;span class='line'&gt;  File "uploader.zip/fancy_urllib/__init__.py", line 367, in do_open
&lt;/span&gt;&lt;span class='line'&gt;urllib2.URLError: &amp;lt;urlopen error [Errno 32] Broken pipe&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;墙很高啊。&lt;/p&gt;

&lt;p&gt;尝试用 tsocks，通过现有的 ssh tunnel 上传，一样的 URLError。有人提到可以设置
https_proxy 环境变量，但是手上又没有 http 代理 (socks5 代理能转成 http 代理么)
。&lt;/p&gt;

&lt;p&gt;本来要放弃了，但是转念一想，刚才我还上传了 GAE 上的一个小网站呢。于是用 google
官方的 GAE SDK 试了下，还真成了。&lt;/p&gt;

&lt;p&gt;goagent 代码其实很简单，需要上传到 GAE 的 app 就在 server/python 目录下。&lt;/p&gt;

&lt;p&gt;所以，到 server/python 目录下，编辑 &lt;code&gt;app.yaml&lt;/code&gt;，把申请的 app 名字填到第一行:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;application: your-app-name&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;然后，把官方的 SDK 下载下来后，&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;/path/to/google_appengine/appcfg.py update .&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;就 OK 了。没被重置，也不需要每次都输密码。如果申请了多个应用做负载均衡，就依次修改 app.yaml，运行 &lt;code&gt;appcfg.py update&lt;/code&gt;，把每一个都部署上。&lt;/p&gt;

&lt;p&gt;go 版本在 server/go, 应该是一样的。&lt;/p&gt;

&lt;p&gt;部署完后 (我搞了四个做负载均衡) 运行 &lt;code&gt;local/proxy.py&lt;/code&gt;。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/bjrpCnSC1cE" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[fedora 系统修复]]></title>
    <link href="http://blog.zhangsen.org/2012/07/fedora-update-disaster.html" />
    <updated>2012-07-18T17:44:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/07/fedora-update-disaster</id>
    <content type="html">&lt;p&gt;一台机器上安的 fedora 17，是用 beta 发布安装的。文档中提到 beta 发布会自动升级到正式版本，不需要改什么配置，所以就一直没在意。但是过了一段时间后，就开始出问题了。&lt;/p&gt;

&lt;p&gt;主要的问题是 &lt;code&gt;yum update&lt;/code&gt; 的时候报一大堆的 404 错误。类似这样的，&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;http://mirrors.sohu.com/fedora/releases/17/Everything/x86_64/os/drpms/LibRaw-0.14.3-3.fc17_0.14.3-4.fc17.x86_64.drpm:
&lt;/span&gt;&lt;span class='line'&gt;[Errno 14] HTTP Error 404 - Not Found :
&lt;/span&gt;&lt;span class='line'&gt;http://mirrors.sohu.com/fedora/releases/17/Everything/x86_64/os/drpms/LibRaw-0.14.3-3.fc17_0.14.3-4.fc17.x86_64.drpm&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;不只 LibRaw 这个包，还有很多，NetworkManager, alsa-plugins-pulseaudio 等等等等。&lt;/p&gt;

&lt;p&gt;这个 404 错误显然是 yum 试图用 drpm 来升级，而它尝试的地址都不对，在源里是不存在的。但是当单独升级每个包的时候，好像不会报错。&lt;/p&gt;

&lt;p&gt;尝试了 &lt;code&gt;yum clean all&lt;/code&gt;, 没什么作用。最后偶然发现很多包的 repo 信息是
&lt;code&gt;@koji-override-0/$releasever&lt;/code&gt;，而正常情况下应该是 fedora, fedora-updates 这样的。&lt;/p&gt;

&lt;p&gt;于是首先用 &lt;code&gt;yum list extras&lt;/code&gt; 找出所有这样的不正常的包.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;yum list extras [glob_exp1] [...]
&lt;/span&gt;&lt;span class='line'&gt;      List  the  packages installed on the system that are not available in any
&lt;/span&gt;&lt;span class='line'&gt;      yum repository listed in the config file.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;把上边得到的列表用 sed/cut 处理一下，用一个 for 循环，一个一个地单独升级，就能修复到正确的 repo 了。&lt;/p&gt;

&lt;p&gt;然后呢&amp;#8230; 发现不好使，有的包还是会尝试用 drpm。&lt;/p&gt;

&lt;p&gt;最后的办法是先暂时把 drpm 支持关掉。升级完再打开。&lt;/p&gt;

&lt;p&gt;而支持 drpm 的特性叫做 &lt;code&gt;presto&lt;/code&gt;, 在 &lt;code&gt;/etc/yum/pluginconf.d/presto.conf&lt;/code&gt; 里配置。(吭爹的名字，八杆子打不着)&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/XqpAsA6mhik" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Python dict 的实现]]></title>
    <link href="http://blog.zhangsen.org/2012/07/python-dict-implementation.html" />
    <updated>2012-07-09T17:01:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/07/python-dict-implementation</id>
    <content type="html">&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Python (cpython) 的 dict 是用哈希表实现的。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;碰撞的处理方法是 open addressing，因为 chaining 的 overhead 太高 (哈希表里记录的只是哈希值和相关的 object 的地址，不记录实际 object，所以如果用链表来做
 chaining 的话，光 next 指针就占去了很多空间)。(不知道我理解得对不对)。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;blockquote&gt;&lt;p&gt;Open addressing is preferred over chaining since the link overhead for&lt;br/&gt;chaining would be substantial (100% with typical malloc overhead).&lt;/p&gt;&lt;/blockquote&gt;


&lt;ul&gt;
&lt;li&gt;一般的哈希表在选择哈希函数时，都希望产生的哈希值尽量随机，但是 python 的哈希函数不是这样的。dict 和其它一些地方使用的哈希函数其实就是 python 的内置函数
&lt;code&gt;hash&lt;/code&gt; ，它的返回值非常的&lt;em&gt;不随机&lt;/em&gt;。比如对于最重要的两种 key，整数和字符串，整数的哈希值就是它本身，而字符串的哈希值计算也很简单。且看&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;&amp;gt;&amp;gt;&amp;gt; map(hash, (0, 1, 2, 3))
&lt;/span&gt;&lt;span class='line'&gt;[0, 1, 2, 3]
&lt;/span&gt;&lt;span class='line'&gt;&amp;gt;&amp;gt;&amp;gt; map(hash, ("namea", "nameb", "namec", "named"))
&lt;/span&gt;&lt;span class='line'&gt;[-1658398457, -1658398460, -1658398459, -1658398462]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;这样的好处是如果 key 是连续的整数或者字符串，几乎不会有碰撞。而且哈希值基本都是连续的，效率也比较高。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;有时候，好处也是坏处。这样做的坏处是，表里会有数据连续地存在一块，而不是相互散开 (这正是哈希表，也称散列表的意义所在啊)，也就是，一旦有碰撞发生，用线性探测的方法来寻找可用位置是绝对不可行的。python 用的探测方法是一种 quadratic
probing，保证不会受到连成块的数据的影响。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;既然是使用 open addressing，也就是说整个哈希表存储在一段连续的内存中，或者说是一个数组 (dict 是用 C 实现的)。这意味着，当数组快满时 (比如超过 2/3)，需要把数组扩大 (resize)。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;python 保证在修改元素的时候不会发生 resize，也就是保证了可以一边遍历 dict，一边修改元素。但是其它的操作就不一定了，所以会有这样的错误:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;&amp;gt;&amp;gt;&amp;gt; a = {1:2, 3:4}
&lt;/span&gt;&lt;span class='line'&gt;&amp;gt;&amp;gt;&amp;gt; for k in a:
&lt;/span&gt;&lt;span class='line'&gt;...  del a[k]
&lt;/span&gt;&lt;span class='line'&gt;...
&lt;/span&gt;&lt;span class='line'&gt;Traceback (most recent call last):
&lt;/span&gt;&lt;span class='line'&gt;  File "&amp;lt;stdin&amp;gt;", line 1, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;span class='line'&gt;RuntimeError: dictionary changed size during iteration
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&amp;gt;&amp;gt;&amp;gt; a = {1:2, 3:4}
&lt;/span&gt;&lt;span class='line'&gt;&amp;gt;&amp;gt;&amp;gt; for k in a:
&lt;/span&gt;&lt;span class='line'&gt;...  a[2*k]=1
&lt;/span&gt;&lt;span class='line'&gt;...
&lt;/span&gt;&lt;span class='line'&gt;Traceback (most recent call last):
&lt;/span&gt;&lt;span class='line'&gt;  File "&amp;lt;stdin&amp;gt;", line 1, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;span class='line'&gt;RuntimeError: dictionary changed size during iteration&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;参考&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;http://www.laurentluce.com/posts/python-dictionary-implementation/&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;http://hg.python.org/cpython/file/tip/Objects/dictobject.c&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;http://en.wikipedia.org/wiki/Hash_table#Collision_resolution&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/ZCwtv2bgW9o" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[python 有这么慢吗]]></title>
    <link href="http://blog.zhangsen.org/2012/06/is-python-so-slower-than-c.html" />
    <updated>2012-06-29T16:01:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/is-python-so-slower-than-c</id>
    <content type="html">&lt;p&gt;逻辑几乎相同的两段代码，python 比 C 慢 50 倍？&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='c'&gt;&lt;span class='line'&gt;&lt;span class="cm"&gt;/* Find the sum of all numbers which are equal to the sum of the factorial of&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cm"&gt;   their digits. */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;f&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&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="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="n"&gt;f&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="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;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;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&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="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;sum&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 class='line'&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&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;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;s&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 class='line'&gt;        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;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 class='line'&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;j&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="kt"&gt;int&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 class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&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 class='line'&gt;&lt;span class="p"&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;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Find the sum of all numbers which are equal to the sum of the factorial of&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# their digits.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&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;factorial&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&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="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&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="n"&gt;limit&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 class='line'&gt;        &lt;span class="n"&gt;s&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 class='line'&gt;        &lt;span class="n"&gt;j&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 class='line'&gt;        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;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 class='line'&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;j&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&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&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&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;/figure&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='line'&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;digit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="mi"&gt;40730&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;real&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mo"&gt;053&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;user&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;850&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;sys&lt;/span&gt;     &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;145&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;./&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;out&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="mi"&gt;40730&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;real&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;115&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;user&lt;/span&gt;    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;111&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;sys&lt;/span&gt;     &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mo"&gt;002&lt;/span&gt;&lt;span class="n"&gt;s&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;/figure&gt;


&lt;p&gt;这是 Project Euler 的第 34 题。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/JLb8sqOvZ-E" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[今日的农村]]></title>
    <link href="http://blog.zhangsen.org/2012/06/todays-countryside.html" />
    <updated>2012-06-28T21:27:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/todays-countryside</id>
    <content type="html">&lt;p&gt;端午回家，又到村庄的农田旁边走了走。原本的良田，现在是这样了。&lt;/p&gt;

&lt;p&gt;农田被圈成了工地，道路早已废弃许久。走在曾经被植被覆盖的乡间，竟然也能被吹一脸土。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://lh3.googleusercontent.com/-jgIeuQjZ0rk/T-xaAI7ehMI/AAAAAAAAAV8/NKWdqRCNav0/s720/IMG_20120623_173646.png"&gt;&lt;/p&gt;

&lt;p&gt;围墙里是曾经的农田。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://lh4.googleusercontent.com/-TMO473kfz70/T-xaLfGWJUI/AAAAAAAAAWU/NDc08C_KU7g/s912/IMG_20120623_173857.png"&gt;&lt;/p&gt;

&lt;p&gt;路对面的耕地还没有被征去，但是农民早不敢投入任何成本，随便种下的葡萄苗，只等着被征的时候多换点拆迁款。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://lh3.googleusercontent.com/-dT5qZBrBZxU/T-xaHg1A-6I/AAAAAAAAAWM/n4KiFgs7eaU/s912/IMG_20120623_173751.png"&gt;&lt;/p&gt;

&lt;p&gt;收拾得这么干净，也是一种无奈吧。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://lh4.googleusercontent.com/-RNlvFnmvoNU/T-xaDmbd75I/AAAAAAAAAWE/p1TiDoXk9WM/s912/IMG_20120623_173755.png"&gt;&lt;/p&gt;

&lt;p&gt;真正让人震惊的，是后边不远处的烟囱。正在建的小区，是打算把附近的村庄拆掉，然后把村民都迁过来的。但是化工厂就在旁边，这是怎样的居心？&lt;/p&gt;

&lt;p&gt;&lt;img src="https://lh4.googleusercontent.com/-eLkE5lS3r7s/T-xf7jhBbcI/AAAAAAAAAWo/nvYyVo83I6U/s912/IMG_20120623_174513.png"&gt;&lt;/p&gt;

&lt;p&gt;现在如火如荼的拆迁，显然就是地方政府的圈钱运动。而中央政府睁只眼闭只眼，道理也很简单，在中国是哪些人还有自己的土地？只有农民还在名义上拥有属于自己的土地。只要动用“拆”这个字，就能把所有人赶到了 70 年产权的商品房里，腾出来的大片土地就又是一笔财源。只要忠厚的中国人都不说话，政府又何乐而不为？&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/bEyAu05kwBE" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[动态分配的二维数组]]></title>
    <link href="http://blog.zhangsen.org/2012/06/2d-array.html" />
    <updated>2012-06-28T20:58:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/2d-array</id>
    <content type="html">&lt;p&gt;在 C 语言里，其实是可以动态分配二维数组的。只调用一次 &lt;code&gt;malloc&lt;/code&gt;，就可以得到一个二维数组，并且支持 &lt;code&gt;p[i][j]&lt;/code&gt; 这样的下标操作。代码如下:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='c'&gt;&lt;span class='line'&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nf"&gt;alloc_2d&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;rows&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;cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;p&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&gt;&lt;span class='line'&gt;    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&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="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&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 class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="n"&gt;p&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="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;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&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;/figure&gt;


&lt;p&gt;释放的时候调用 &lt;code&gt;free&lt;/code&gt; 即可。&lt;/p&gt;

&lt;p&gt;再看我之前那些用一维数组模拟二维数组的拙劣代码，真是不堪回首。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/rMkIoY3PvJQ" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[计算区间内的素数]]></title>
    <link href="http://blog.zhangsen.org/2012/06/primes-in-a-range.html" />
    <updated>2012-06-27T20:47:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/primes-in-a-range</id>
    <content type="html">&lt;p&gt;生成素数的一般方法是用“筛”，古老的 Sieve of Eratosthenes，来生成 [1,n] 之间的所有素数。这里的问题稍有变化，要求计算某个区间 [m,n] 内的素数，其中 m 和 n 都有可能很大，但是 n-m 不大。&lt;/p&gt;

&lt;p&gt;这其实是 SPOJ 上的第二道题 (&lt;a href="http://www.spoj.pl/problems/PRIME1/"&gt;PRIME1&lt;/a&gt;)。&lt;/p&gt;

&lt;p&gt;由于 m 和 n 很大，所以不能用试除法 (trial division)，而且 Sieve of Eratosthenes
也不可行。&lt;/p&gt;

&lt;p&gt;这种情况可以用分段的筛 (segmented sieve)。也就是先用 sieve 计算出 [1,sqrt(n)]
上的素数。然后用这个素数表，在 [m,n] 上再次应用 sieve，得到所求的素数。两次的筛都不是很大，可以放在内存中，而且速度也可以接受。如果 n-m 还是很大，还可以再次分成几段来做 sieve，这是&lt;a href="http://programmingpraxis.com/2010/02/05/segmented-sieve-of-eratosthenes/"&gt;这里&lt;/a&gt;的做法。
(我怎么觉得后面这种情况才是 segmented sieve 呢?)&lt;/p&gt;

&lt;p&gt;一个类似的用这种分段策略的题目是，假设一个文件里有 4 billion 个整数，数字都是普通的 int，也就是有 32 位。要求找到一个不在这个文件里的整数，限制可用内存为 10MB
。&lt;/p&gt;

&lt;p&gt;用一般的 bitmap 肯定是不行的。可以采用分段策略，通过两次遍历完成。把 2&lt;sup&gt;32&lt;/sup&gt; 这个区间分成若干段，第一次遍历求每一个区间中数字出现的个数。然后找出一个必然存在缺失数字的区间，对这个小的区间创建 bitmap，进行第二次遍历，找到一个缺失的数字。空间复杂度满足要求，因为假设有 M 个小区间，每个区间有 N 个数，那么 &lt;code&gt;M*N=2^32&lt;/code&gt;，第一次遍历需要 &lt;code&gt;M*4B&lt;/code&gt;，第二次遍历需要 &lt;code&gt;N*4B&lt;/code&gt; (假设 bitmap 都用 int 数组)。所以 M
和 N 都取为 2&lt;sup&gt;16&lt;/sup&gt; = 65536 即可。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/w6a5HBG-N5Y" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[dup3, pipe2, epoll_create1]]></title>
    <link href="http://blog.zhangsen.org/2012/06/dup3-pipe2-epoll-create1.html" />
    <updated>2012-06-27T09:51:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/dup3-pipe2-epoll-create1</id>
    <content type="html">&lt;p&gt;dup, pipe, epoll_create 这些函数都有一些变种，&lt;code&gt;dup3&lt;/code&gt;, &lt;code&gt;pipe2&lt;/code&gt;, &lt;code&gt;epoll_create1&lt;/code&gt;
。为什么会这样？原因是这些接口设计时考虑不足，导致无法进行扩展，当新需求出现的时候，只能再添加新的接口。&lt;/p&gt;

&lt;p&gt;这些函数有什么相同之处呢，它们都是用来创建新的文件描述符的 (file descriptor)。这个需求就是跟文件描述符相关。&lt;/p&gt;

&lt;p&gt;在通过 fork/exec 创建一个新进程的时候，默认的行为是子进程继承父进程的所有已打开的文件。为了安全性，一般会把文件设成 close-on-exec，也就是说执行 exec 的时候，自动把文件关闭。否则的话，父进程的文件就会泄漏给子进程。&lt;/p&gt;

&lt;p&gt;比如浏览器里，假设一个 tab 是银行付款页面，另一个 tab 是“某个”页面，这个页面需要用一个 plugin，而浏览器通过 fork/exec 来运行这个 plugin。如果文件描述符没有设置为 close-on-exec，那么银行页面的文件就有可能泄漏给这个 plugin。然后&amp;#8230;&lt;/p&gt;

&lt;p&gt;所以一般都会通过 &lt;code&gt;fcntl&lt;/code&gt; 来设置一个 flag, &lt;code&gt;FD_CLOEXEC&lt;/code&gt;，保证在 fork/exec 的时候自动关闭文件。但是由于 &lt;code&gt;open&lt;/code&gt; 和 &lt;code&gt;fcntl&lt;/code&gt; 之间总是存在一定的时间差，所以在多线程的程序里会有潜在的危险。一个办法是用锁，保证 open 和 fcntl 之间不会进行 fork，但是这并不可行 (且看引用原文的描述)。&lt;/p&gt;

&lt;p&gt;最好的办法就是给 open 添加一个 flag，使得文件在打开时就已经设为 close-on-exec。&lt;/p&gt;

&lt;p&gt;但是&amp;#8230; 能打开文件 (也就是创建文件描述符) 的函数不只有 open。由于 UNIX 众所周知的设计特点，socket/accept/pipe/dup/epoll 都能创建文件描述符。而最大的问题是，不是所有的函数都像 open 那样有一个 &lt;code&gt;flags&lt;/code&gt; 参数。比如 &lt;code&gt;int pipe(int pipefd[2])&lt;/code&gt;。管道固然是个绝佳的概念，但是谁也没想到，后人竟然想对管道设置 flag。&lt;/p&gt;

&lt;p&gt;但是为了保证原子性得设置 close-on-exec，必须要有 flag 参数，所以对这些函数只能创建新的接口，&lt;code&gt;dup3&lt;/code&gt;, &lt;code&gt;pipe2&lt;/code&gt; 等等就是这样来的。这个解决方案不算完美，但也没有更好的办法了 (比如 linus 提出过一个“间接系统调用”的方案)。&lt;/p&gt;

&lt;p&gt;而另一些函数，比如 &lt;code&gt;int socket(int domain, int type, int protocol)&lt;/code&gt;，虽然没有
flag，但有一个 &lt;code&gt;type&lt;/code&gt; 参数。由于 type 的取值范围很有限，而且 type 和 flag 还算有点相似，所以开发者决定复用这个参数，把 &lt;code&gt;SOCK_CLOEXEC&lt;/code&gt; 看作新的 type。这样函数接口就不需要修改了。&lt;/p&gt;

&lt;p&gt;这样，所有能创建文件描述符的接口就都(相当于)有 flag 参数了，不仅可以用于设置
close-on-exec，而且也能方便将来的其它扩展。比如 &lt;code&gt;XXX_NONBLOCK&lt;/code&gt; (现在已有)，和提了好久的 non-sequential file descriptor 的支持。&lt;/p&gt;

&lt;p&gt;引用: &lt;a href="http://udrepper.livejournal.com/20407.html"&gt;udrepper.livejournal.com&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/XIsBHED0TjU" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[firefox 被某智篡改的主页]]></title>
    <link href="http://blog.zhangsen.org/2012/06/chinese-firefox.html" />
    <updated>2012-06-25T21:34:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/chinese-firefox</id>
    <content type="html">&lt;p&gt;端午回家，升级了下家里电脑的 firefox，发现主页竟然给改成 firefox.com.cn 上的一个地址了，又是某智做的好事。而且是默认项，“恢复默认设置”也不管用。解决办法是设成 &lt;code&gt;about:home&lt;/code&gt;，就能恢复 firefox (真正)默认的主页了。&lt;/p&gt;

&lt;p&gt;某智现在做的，还算是在忍受范围内，没有之前那一堆“火狐魔镜”之类的东西了。不过依然让人不爽，比如默认搜索引擎设成 baidu ，这符合 mozilla 的官方政策吗？再次怀疑
mozilla 搞这些的必要性。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/5_LE8l_5lyE" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[newline]]></title>
    <link href="http://blog.zhangsen.org/2012/06/newline.html" />
    <updated>2012-06-21T14:42:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/newline</id>
    <content type="html">&lt;p&gt;翻译是一件看起来简单做起来难的事。在维基百科上查到了这么一段话，想翻译成中文，吭吃吭吃好不容易写完，感觉却还是佶屈聱牙。&lt;/p&gt;

&lt;p&gt;&amp;#8220;There is also some confusion whether newlines terminate or separate lines. If a
newline is considered a separator, there will be no newline after the last line
of a file. The general convention on most systems is to add a newline even
after the last line, i.e. to treat newline as a line terminator. Some programs
have problems processing the last line of a file if it is not newline
terminated. Conversely, programs that expect newline to be used as a separator
will interpret a final newline as starting a new (empty) line.&amp;#8221;  (&lt;a href="http://en.wikipedia.org/wiki/Newline"&gt;en.wikipedia.org&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;“换行字符可以看作是行的结束符，也可以看作行之间的分隔符，这两种处理方式之间存在一些歧义。如果换行字符被当作分隔符，那么文件的最后一行就不需要再有换行字符。但是多数系统的做法是在最后一行的后面也加上一个换行字符，也就是把换行字符看作是行的结束符。这样的程序在处理末行没有换行字符的文件时，可能会存在问题。相反地，有的程序把换行符看作分隔符，就会把最末尾的换行字符看作是新行的开始，也就是多出了一个空行。”  (&lt;a href="http://zh.wikipedia.org/wiki/%E6%8F%9B%E8%A1%8C"&gt;zh.wikipedia.org&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;P.S. 写了个简单的 tail 程序，却总是多出一行来。结果发现，用 getline 等函数其实就相当于把换行符当作了分隔符，而不是结束符 (C++ 的 getline 的定义就是 &lt;code&gt;getline
( istream&amp;amp; is, string&amp;amp; str, char delim )&lt;/code&gt;, 指明了 &amp;#8220;delim&amp;#8221;)。所以最后的这个换行应该特殊处理。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/XXALZ2QdQjA" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[asdf]]></title>
    <link href="http://blog.zhangsen.org/2012/06/asdf.html" />
    <updated>2012-06-20T23:04:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/asdf</id>
    <content type="html">&lt;p&gt;MS 出平板了？今天看到的这段话还真准，(apple) rarely makes a random jump into a
disconnected market just to chase a shiny new trinket (I&amp;#8217;m looking at you,
Microsoft, and your Bing, MSN, and Zune debacles).&lt;/p&gt;

&lt;p&gt;http://www.quora.com/Apple-Inc-2/Is-Apple-really-going-to-try-and-kill-Google&lt;/p&gt;

&lt;p&gt;拭目以待吧。&lt;/p&gt;

&lt;p&gt;P.S. 我本来要发 twitter 的，结果这字数限制实在让人崩溃，一句话都说不完。还是自家地盘爽。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/0GoPd68mq5Q" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GNU Screen: altscreen on]]></title>
    <link href="http://blog.zhangsen.org/2012/06/altscreen-on.html" />
    <updated>2012-06-19T13:06:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/altscreen-on</id>
    <content type="html">&lt;p&gt;折腾起来，真是一发而不可收。&lt;/p&gt;

&lt;p&gt;刚发现了 screen 的这个选项，使能之后，退出程序或者按 ctrl-z 之后不会留下“残余”。&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;altscreen on|off
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;If  set to on, "alternate screen" support is enabled in virtual terminals,
&lt;/span&gt;&lt;span class='line'&gt;just like in xterm.  Initial setting is `off'.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(git 需要设置下 pager，&lt;a href="http://linuxtips.manki.in/2012/02/making-git-commands-clear-screen-when.html"&gt;linuxtips.manki.in&lt;/a&gt;):&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;git config --global core.pager 'less -+X -+F'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;

&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/4WVsoGQS5A0" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Colorful Term]]></title>
    <link href="http://blog.zhangsen.org/2012/06/colorful-term.html" />
    <updated>2012-06-19T10:35:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/colorful-term</id>
    <content type="html">&lt;p&gt;虽然之前折腾过256 色的 terminal，但是总觉得效果好像不大对。下边是正确的折腾步骤。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;首先环境变量 TERM 应该设成 xterm-256color (保证你有这个文件
/usr/share/terminfo/x/xterm-256color)。&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;在 &lt;code&gt;~/.bashrc&lt;/code&gt; 里写&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TERM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xterm-256color
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;但是要注意的是，这一行必须写在导入系统设置之前，也就是这样&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# User specific aliases and functions&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TERM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xterm-256color
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Source global definitions&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f /etc/bashrc &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        . /etc/bashrc
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f /etc/profile &lt;span class="o"&gt;]&lt;/span&gt;;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /etc/profile
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&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;/figure&gt;


&lt;p&gt;否则，就是这副很普通的样子，&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.zhangsen.org/images/p/ls-plain.png"&gt;&lt;/p&gt;

&lt;p&gt;正确的话是这个俨然闪闪放光的样子，&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.zhangsen.org/images/p/ls-good.png"&gt;&lt;/p&gt;

&lt;p&gt;所以默认的 .bashrc 把 &amp;#8220;User specific aliases and functions&amp;#8221; 放在前边，还是大有深意的。&lt;/p&gt;

&lt;p&gt;(当然，影响的只是 &lt;code&gt;ls&lt;/code&gt;，vim 等应该不受影响。)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;screen 里不需要特殊的配置。有人提到需要换成 screen-256color (在 .screenrc 里写 &lt;code&gt;term screen-256color&lt;/code&gt;)，但是我在 fedora 17 上没遇到什么问题。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;然后是 solarized 的主题，就不细说了，把 gnome-terminal 和 vim 设好就 ok。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;P.S. vim 的 &lt;code&gt;set t_Co=256&lt;/code&gt;，貌似是没有任何作用，跟我用了 solarized 的
colorscheme 有关？不管怎么设，vim 和 gvim 都是一个样子的。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/XJ-6Ccb4Flk" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Perfect]]></title>
    <link href="http://blog.zhangsen.org/2012/06/perfect.html" />
    <updated>2012-06-15T16:19:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/perfect</id>
    <content type="html">&lt;p&gt;今天才突然意识到，&amp;#8221;perfect&amp;#8221; 有“完全”的意思。比如“完全平方数”是 &amp;#8220;perfect square&amp;#8221;
，“现在完成式”是 &amp;#8220;present perfect&amp;#8221;。&lt;/p&gt;

&lt;p&gt;P.S. 数学小贴士：完全平方数都有奇数个因子，其它整数都有偶数个因子。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/kI57u30qoEY" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Migrate to Octopress - follow up]]></title>
    <link href="http://blog.zhangsen.org/2012/06/migrate-to-octopress-follow-up.html" />
    <updated>2012-06-14T21:45:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/migrate-to-octopress-follow-up</id>
    <content type="html">&lt;p&gt;部署完发现问题还是挺多的。主要就是几个链接没有了，包括 feed, archive 等等。&lt;/p&gt;

&lt;p&gt;搜索了一番，&lt;a href="http://approache.com/blog/migrating-from-blogger-to-octopress/"&gt;这里&lt;/a&gt; 提到了对 blogger 的 redirect。代码在这 (&lt;a href="https://github.com/dnagir/approache-redirects/blob/master/app.rb"&gt;github.com&lt;/a&gt;)。&lt;/p&gt;

&lt;p&gt;其实就是几条 URL 匹配规则。因为 octopress 虽然基本是静态的，但是其实是有一个小的 web 框架的 (sinatra)，所以还是比较灵活。&lt;/p&gt;

&lt;p&gt;我把我用的 heroku 部署相关的东西放这了 (&lt;a href="https://github.com/zhangsen/octopress-heroku-deploy"&gt;github.com&lt;/a&gt;)。octopress 需要的 patch 在这 (&lt;a href="https://github.com/zhangsen/octopress/commit/2215aaad70da4b4e4017c43afa8b6a08ab1905b9"&gt;github.com&lt;/a&gt;)。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/g3NId95WyTw" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Migrate to Octopress]]></title>
    <link href="http://blog.zhangsen.org/2012/06/migrate-to-octopress.html" />
    <updated>2012-06-14T17:42:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/06/migrate-to-octopress</id>
    <content type="html">&lt;p&gt;心血来潮，把 blog 换到了 octopress。用了几年的 blogger，以前看到
octopress/jekyll 的时候，从来都觉得没什么，blogger 这种 It just works™ 的就很好。结果昨天重装了个系统，头脑一热，顺带把 blog 也换了。人啊，奇怪的生物。&lt;/p&gt;

&lt;p&gt;我这人特别不喜欢遇到 404 的链接，所以到了我迁移网站的时候，就理所当然要努力保证兼容性了。感谢 octopress，其实就是改个配置的事儿。&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;# file : _config.yml
&lt;/span&gt;&lt;span class='line'&gt;permalink: /:year/:month/:title.html&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;然后用&lt;a href="https://gist.github.com/2928871"&gt;这个小工具&lt;/a&gt;把 blogger 上原来的文章和留言都抓过来。这段代码还有不少版本，我也是根据前人的稍微修改了下，具体使用的过程网上也有不少文章。这里还要感谢 blogger，把打包下载做得这么容易，让用户很容易就跑了。什么是大国心态?&lt;/p&gt;

&lt;p&gt;然后由于我之前(好像)用的是 feedburner，所以这块就省事了，订阅我博客的人应该不需要什么改动。&lt;/p&gt;

&lt;p&gt;然后写篇声明，写完后把 DNS 一改，就 ok 了，无缝迁移，哈哈。目前发现只有各个月的
archive 页面丢掉了，其它链接应该没有 404 的。&lt;/p&gt;

&lt;p&gt;还有一点是，之前就开始用 disqus，所以留言也都还保留着。这个也很好，感谢 disqus。&lt;/p&gt;

&lt;p&gt;网站放在 heroku 上，因为我不是很愿意把 blog 内容搞个 public repo，放到 github
上。但是 octopress 文档里的部署到 heroku 的方法不很 (很不!) 爽，因为要把生成的乱七八糟的内容都加到 repo 里。所以找了&lt;a href="http://joshuawood.net/how-to-deploy-jekyll-slash-octopress-to-heroku/"&gt;一个办法&lt;/a&gt;，给 octopress 打了个补丁:&lt;/p&gt;

&lt;p&gt;还搜到了一个办法是利用 heroku 的 custom buildpack，嗯，太复杂。&lt;/p&gt;

&lt;p&gt;octopress 是挺漂亮的，但是在 google 的过程中，发现大家都长一个样&amp;#8230;&lt;/p&gt;

&lt;p&gt;用 markdown 写的第一篇 blog，撒花。&lt;/p&gt;

&lt;p&gt;P.S.&lt;/p&gt;

&lt;p&gt;feed 还是出问题了，如果之前订阅的是
http://blog.zhangsen.org/feeds/posts/default, Google Reader 其实记录的仍然是这个地址，而不是重定向的 feedburner，TODO, FIXME。&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/sss6bg956SU" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[rbtree in linux kernel]]></title>
    <link href="http://blog.zhangsen.org/2012/05/rbtree-in-linux-kernel.html" />
    <updated>2012-05-27T16:48:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/05/rbtree-in-linux-kernel</id>
    <content type="html">&lt;div class='post'&gt;
正在(重新)看算法导论。这是看 http://lwn.net/Articles/184495/ 的一个小结。&lt;br /&gt;&lt;br /&gt;红黑树作为近似平衡的二叉搜索树，由于高效的操作，尤其是插入和删除能很快的 rebalancing (不会  go off for an indeterminate period of time rebalancing itself)，所以在 kernel 里有很多应用。&lt;br /&gt;&lt;br /&gt;kernel 里的红黑树在 lib/rbtree.c 里实现。为了效率，rbtree 不是按照黑盒子的方式实现的，用户必须实现自己的插入和搜索函数。因为如果用函数指针来指定比较操作，由此带来的大量的间接的函数调用势必会影响效率。&lt;br /&gt;&lt;br /&gt;rbtree 的另一个特点是，跟 kernel 里的 list 类似，struct rb_node 是作为成员嵌套进用户的数据结构的，而不是像通常的课本上那样，定义一个节点的结构，然后把 satellite data 放进这个结构。rbtree 都是在这个 rb_node 上进行操作，如果涉及到了实际数据，比如插入和搜索，就需要用户自己实现。&lt;br /&gt;&lt;br /&gt;从一个 struct rb_node 取得包含它的 struct 可以通过  container_of() 或者 rb_entry() 来实现。&lt;br /&gt;&lt;br /&gt;rb_node 里包含左右子节点的指针，父节点的指针，还有节点的颜色。特殊之处在于用了一个 unsigned long 来同时记录颜色和父节点的指针。貌似是依赖于指针的最后两位一定是 0。所以可以把最后一位用来标记颜色。这样就省了一个 int。&lt;br /&gt;&lt;br /&gt;搜索就是普通 BST 的搜索，遍历一下即可，没有特殊的地方。&lt;br /&gt;&lt;br /&gt;而插入的时候，需要调用 rbtree 的几个函数。用户需要自己实现找到要插入的位置，然后调用 rb_link_node 来插入新节点，最后调用 rb_insert_color 来 fixup (recoloring)。&lt;br /&gt;&lt;br /&gt;rbtree 还提供了几个函数来实现遍历，rb_first, rb_last, rb_next, rb_prev。&lt;br /&gt;&lt;br /&gt;rbtree 还提供了对 augmented rbtree 的支持。Documentation/rbtree.txt 举了一个 interval tree 的例子。用户需要在插入和删除节点的时候需要提供合适的 callback 来处理 augmentation 信息。&lt;br /&gt;&lt;br /&gt;P.S. 最近都是在 google docs 里写东西，然后遇到适合发布的就贴到 blog 里来。这样子的感觉好多了，不会在 blog 里留一堆废掉的草稿。当然，发布的只是很小一部分，比如已经写了将近 40 页的算法导论的笔记 (而且看了还不到一半)，估计不会发了 ;)&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/xVYBmYnEDpw" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[git internals]]></title>
    <link href="http://blog.zhangsen.org/2012/04/git-internals.html" />
    <updated>2012-04-19T21:14:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/04/git-internals</id>
    <content type="html">&lt;div class='post'&gt;
这是在 beihang open source club 讲 git 的讲稿。正好借着这个机会把之前看的东西整理整理。其实好几个月之前就跟 grissiom 大概聊过这些内容了，但现在才找到机会(和动力)写下来。&lt;br /&gt;&lt;br /&gt;这有带图片和(一点)格式的版本: &lt;a href="https://docs.google.com/document/pub?id=1FFssCYnbMgKk9rEEctDWz23Ne8WV4Uy5rOIehX0Rdkw"&gt;https://docs.google.com/document/pub?id=1FFssCYnbMgKk9rEEctDWz23Ne8WV4Uy5rOIehX0Rdkw&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;0.&lt;br /&gt;&lt;br /&gt;git 本质上是一个 content-addressable filesystem，然后在其上做了个 VCS 的界面。&lt;br /&gt;&lt;br /&gt;git 一开始的设计都是围绕着怎么操作这个文件系统来的，所以原来的用户界面不是“那么的”友好。现在的界面已经好多了，但是明白底下这个文件系统的机制，能帮助你更好的发掘 git 的潜力。&lt;br /&gt;&lt;br /&gt;prerequisite: 读者应该对 git 的 基本使用方法，尤其是 staging area 有所了解。可以看此文 http://progit.org/2011/07/11/reset.html 的 The Three Trees of Git 一节。&lt;br /&gt;&lt;br /&gt;1. plumbing 和 porcelain&lt;br /&gt;&lt;br /&gt;git 一开始并不是想提供一个 VCS，而是一个 VCS toolkit。所以 git 有一些很底层的命令，由这些命令再组成更上层的界面。(UNIX 哲学)&lt;br /&gt;&lt;br /&gt;底层的这些命令称为 plumbing commands，上层的命令称为 porcelain commands。&lt;br /&gt;&lt;br /&gt;例子：&lt;br /&gt;&lt;br /&gt;$ echo &amp;#8216;test content&amp;#8217; | git hash-object -w &amp;#8211;stdin&lt;br /&gt;$ git cat-file -p d670460b4b4a&lt;br /&gt;&lt;br /&gt;2. .git 目录结构&lt;br /&gt;&lt;br /&gt;$ git init&lt;br /&gt;Initialized empty Git repository in /home/jesse/src/gittalk/.git/&lt;br /&gt;&lt;br /&gt;$ ls -a&lt;br /&gt;.&amp;nbsp; ..&amp;nbsp; .git&lt;br /&gt;&lt;br /&gt;$ ls -F .git&lt;br /&gt;config&amp;nbsp; description&amp;nbsp; HEAD&amp;nbsp; hooks/&amp;nbsp; info/&amp;nbsp; objects/&amp;nbsp; refs/&lt;br /&gt;&lt;br /&gt;$ touch a&lt;br /&gt;$ git add a&lt;br /&gt;$ ls .git -F&lt;br /&gt;config&amp;nbsp; description&amp;nbsp; HEAD&amp;nbsp; hooks/&amp;nbsp; index&amp;nbsp; info/&amp;nbsp; objects/&amp;nbsp; refs/&lt;br /&gt;&lt;br /&gt;git 运行所需要的所有文件都在 .git 里。&lt;br /&gt;&lt;br /&gt;config: 配置文件&lt;br /&gt;description: GitWeb 用。&lt;br /&gt;info: .git/info/exclude&lt;br /&gt;hooks: 脚本&lt;br /&gt;&lt;br /&gt;HEAD, index, objects, refs: git 的核心。&lt;br /&gt;&lt;br /&gt;objects: 所有的数据&lt;br /&gt;refs: 指向 commit object 的指针&lt;br /&gt;HEAD: 当前 branch&lt;br /&gt;index: staging area 信息&lt;br /&gt;&lt;br /&gt;3. content-addressable filesystem&lt;br /&gt;&lt;br /&gt;content-addressable filesystem，什么意思？就是一个简单的 key-value 系统。&lt;br /&gt;&lt;br /&gt;git hash-object 把一个 object 作为 value 存入文件系统，然后返回这个 object 的 key。key 是一个长度为 40 的 sha1 值。&lt;br /&gt;&lt;br /&gt;$ find .git/objects/ -type f&lt;br /&gt;$&lt;br /&gt;$ echo &amp;#8216;test content&amp;#8217; | git hash-object -w &amp;#8211;stdin&lt;br /&gt;d670460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;$&lt;br /&gt;$ find .git/objects/ -type f&lt;br /&gt;.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;&lt;br /&gt;存入一个 value 后，可以通过 key 把它读取出来：&lt;br /&gt;&lt;br /&gt;$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;test content&lt;br /&gt;&lt;br /&gt;这里的 object 是一个字符串。&lt;br /&gt;&lt;br /&gt;hash-object 也可以读取文件内容作为 value 存入：&lt;br /&gt;&lt;br /&gt;$ echo &amp;#8216;version 1&amp;#8217; &amp;gt; test.txt&lt;br /&gt;$ git hash-object -w test.txt&lt;br /&gt;83baae61804e65cc73a7201a7252750c76066a30&lt;br /&gt;&lt;br /&gt;试试对文件做点修改：&lt;br /&gt;&lt;br /&gt;$ echo &amp;#8216;version 2&amp;#8217; &amp;gt; test.txt&lt;br /&gt;$ git hash-object -w test.txt&lt;br /&gt;1f7a7a472abf3dd9643fd615f6da379c4acb3e3a&lt;br /&gt;&lt;br /&gt;现在文件系统或者数据库里有三个 object 了：&lt;br /&gt;&lt;br /&gt;$ find .git/objects -type f&lt;br /&gt;.git/objects/83/baae61804e65cc73a7201a7252750c76066a30&lt;br /&gt;.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a&lt;br /&gt;&lt;br /&gt;也就是说，git 的操作是以文件为单位的，一个文件作出修改后，都以新的 object 存入。&lt;br /&gt;&lt;br /&gt;object 存入时，用 zip 算法进行压缩，然后用 sha1 算法计算 key。&lt;br /&gt;&lt;br /&gt;4. objects&lt;br /&gt;&lt;br /&gt;注意到，上边的三个 object 存的都是文件内容，没有文件名或者创建时间这些信息，也没有用我们平时用 git commit 时填入的 commit message 等等。&lt;br /&gt;&lt;br /&gt;git 有若干种 object，上边用 hash-object 创建的是 blob 类型的 object。&lt;br /&gt;&lt;br /&gt;$ git cat-file -t 1f7a7a472a&lt;br /&gt;blob&lt;br /&gt;&lt;br /&gt;cat-file -t 打印某个 object 的类型信息。&lt;br /&gt;&lt;br /&gt;还有两种比较重要的 object。tree object 和 commit object。tree 对应目录树的概念，把 blob 组织起来。而 commit object 与 tree 对应，并且 commit 之间有 parent-child 的关系，这样就能形成 VCS 的历史记录了。&lt;br /&gt;&lt;br /&gt;5. tree&lt;br /&gt;&lt;br /&gt;tree 类似于 UNIX 系统上的目录。一个 tree object 包含一组 tree entry。每个 tree entry 是一个 blob (其实是一个 blob 的 sha1 值)，或者是一个 subtree (的 sha1 值), 以及它们的名字、类型、权限。&lt;br /&gt;&lt;br /&gt;$ git cat-file -p master^{tree}&lt;br /&gt;100644 blob a906cb2a4a904a152e80877d4088654daad0c859&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; README&lt;br /&gt;100644 blob 8f94139338f9404f26296befa88755fc2598c289&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Rakefile&lt;br /&gt;040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lib&lt;br /&gt;&lt;br /&gt;master^{tree} 是 master 分支上最后一个 commit 所指向的 tree。这个 tree object 包含三个 entry (也就是三个 sha1 值)，其中两个是 blob，第三个是另一个 tree object。这三个 sha1 值还有对应的 mode 和 filename。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;git 创建 tree 的方式是使用当前 staging area 的内容创建一个 tree object。所以需要先创建 staging-area 或者 index。&lt;br /&gt;&lt;br /&gt;创建 index 的命令是 git update-index&lt;br /&gt;&lt;br /&gt;$ git update-index &amp;#8211;add &amp;#8211;cacheinfo 100644 \&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 83baae61804e65cc73a7201a7252750c76066a30 test.txt&lt;br /&gt;&lt;br /&gt;把 83baae 这个 blob object (包含“version 1&amp;#8221;的那个)，按照指定的 mode 和名字，加入 index。&lt;br /&gt;&lt;br /&gt;100644 表示一个 normal file。文件还可以设为可执行，或者是符号链接。但是 git 支持的权限很有限，是 UNIX 上文件模型的子集。&lt;br /&gt;&lt;br /&gt;然后用 git write-tree 创建 tree object。&lt;br /&gt;&lt;br /&gt;$ git write-tree&lt;br /&gt;d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;&lt;br /&gt;$ find .git/objects/ -type f&lt;br /&gt;.git/objects/83/baae61804e65cc73a7201a7252750c76066a30&lt;br /&gt;.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a&lt;br /&gt;&lt;br /&gt;$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;100644 blob 83baae61804e65cc73a7201a7252750c76066a30&amp;nbsp;&amp;nbsp;&amp;nbsp; test.txt&lt;br /&gt;&lt;br /&gt;$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;tree&lt;br /&gt;&lt;br /&gt;这样就创建了一个新的 tree object，它包含一个文件 test.txt。现在一共有三个 blob 和一个 tree 了。object 文件是包含类型信息的，git 能够知道 d8329fc 是个 tree object。&lt;br /&gt;&lt;br /&gt;再创建一个 tree object。把当前目录下的 test.txt (包含&amp;#8221;version 2&amp;#8221;) 加入，并且加入一个新文件 new.txt。&lt;br /&gt;&lt;br /&gt;$ git update-index test.txt&lt;br /&gt;$ echo &amp;#8216;new file&amp;#8217; &amp;gt; new.txt&lt;br /&gt;$ git update-index &amp;#8211;add new.txt&lt;br /&gt;&lt;br /&gt;$ git write-tree&lt;br /&gt;0155eb4229851634a0f03eb265b69f5a2d56f341&lt;br /&gt;&lt;br /&gt;$ git cat-file -p 0155eb422&lt;br /&gt;100644 blob fa49b077972391ad58037050f2a75f74e3671e92&amp;nbsp;&amp;nbsp;&amp;nbsp; new.txt&lt;br /&gt;100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a&amp;nbsp;&amp;nbsp;&amp;nbsp; test.txt&lt;br /&gt;&lt;br /&gt;这个 tree object 包含两个文件。&lt;br /&gt;&lt;br /&gt;虽然 tree object 是有结构的，但仍然是很基本的数据。我们可以把之前创建的第一个 tree 读入staging area (现在的 staging area 是第二个 tree 里的东西)，并且放进一个子目录。&lt;br /&gt;&lt;br /&gt;$ git read-tree &amp;#8211;prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;&lt;br /&gt;$ git write-tree&lt;br /&gt;3c4e9cd789d88d8d89c1073707c3585e41b0e614&lt;br /&gt;&lt;br /&gt;$ git cat-file -p 3c4e&lt;br /&gt;040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; bak&lt;br /&gt;100644 blob fa49b077972391ad58037050f2a75f74e3671e92&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new.txt&lt;br /&gt;100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; test.txt&lt;br /&gt;&lt;br /&gt;新建的第三个 tree 相当于包含前两个 tree 的内容。(注意，这些操作都是在 index 和后端存储之间进行的，没有动到 working dir。)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6. commit object&lt;br /&gt;&lt;br /&gt;文件的基本信息在 tree 里保存，那 tree 的基本信息呢？比如创建 tree 的时间、人物、原因。所以 git 又提供了 commit object 保存这些信息。&lt;br /&gt;&lt;br /&gt;$ echo &amp;#8216;first commit&amp;#8217; | git commit-tree d8329f&lt;br /&gt;9fa147d9147f7dbbfa641ebe2992a336bc1a4c93&lt;br /&gt;&lt;br /&gt;git commit-tree 能创建一个新的 commit object。&lt;br /&gt;&lt;br /&gt;$ git cat-file -p 9fa147d9&lt;br /&gt;tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;author Jesse Zhang &amp;lt;xxx@xxx&amp;gt; 1334569863 +0800&lt;br /&gt;committer Jesse Zhang &amp;lt;xxx@xxx&amp;gt; 1334569863 +0800&lt;br /&gt;&lt;br /&gt;first commit&lt;br /&gt;&lt;br /&gt;现在能看到 git log 的样子了。&lt;br /&gt;&lt;br /&gt;再创建两个 commit。&lt;br /&gt;&lt;br /&gt;$ echo &amp;#8216;second commit&amp;#8217; | git commit-tree 0155eb -p 9fa147d91&lt;br /&gt;b951b414a680c16e48c095a080b435874a5da79e&lt;br /&gt;&lt;br /&gt;$ echo &amp;#8216;third commit&amp;#8217;&amp;nbsp; | git commit-tree 3c4e9c -p b951b414&lt;br /&gt;29c0bd0cd9084ad30e0eaca38632500d700d6644&lt;br /&gt;&lt;br /&gt;这两个 commit 都用 -p 指定了 parent commit。第一个 commit 没有指定 parent，所以是一个 initial commit，或者 root commit，或者 orphan commit。&lt;br /&gt;&lt;br /&gt;现在已经能用 git log 了。&lt;br /&gt;&lt;br /&gt;$ git log &amp;#8211;stat 29c0bd0&lt;br /&gt;commit 29c0bd0cd9084ad30e0eaca38632500d700d6644&lt;br /&gt;Author: Jesse Zhang &amp;lt;xxx&amp;gt;&lt;br /&gt;Date:&amp;nbsp;&amp;nbsp; Mon Apr 16 17:54:25 2012 +0800&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; third commit&lt;br /&gt;&lt;br /&gt;bak/test.txt |&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 +&lt;br /&gt;1 files changed, 1 insertions(+), 0 deletions(-)&lt;br /&gt;&lt;br /&gt;commit b951b414a680c16e48c095a080b435874a5da79e&lt;br /&gt;Author: Jesse Zhang &amp;lt;xxx&amp;gt;&lt;br /&gt;Date:&amp;nbsp;&amp;nbsp; Mon Apr 16 17:54:12 2012 +0800&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; second commit&lt;br /&gt;&lt;br /&gt;new.txt&amp;nbsp; |&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 +&lt;br /&gt;test.txt |&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 +-&lt;br /&gt;2 files changed, 2 insertions(+), 1 deletions(-)&lt;br /&gt;&lt;br /&gt;commit 9fa147d9147f7dbbfa641ebe2992a336bc1a4c93&lt;br /&gt;Author: Jesse Zhang &amp;lt;xxx&amp;gt;&lt;br /&gt;Date:&amp;nbsp;&amp;nbsp; Mon Apr 16 17:51:03 2012 +0800&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; first commit&lt;br /&gt;&lt;br /&gt;test.txt |&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 +&lt;br /&gt;1 files changed, 1 insertions(+), 0 deletions(-)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7. git references&lt;br /&gt;&lt;br /&gt;使用上边提到的 objects，已经可以建立起完整的历史了，但是所有的 key 都是 sha1 值，不便使用。利用 references，或者 refs，可以把 sha1 值与一个名字联系起来。&lt;br /&gt;&lt;br /&gt;一个 ref 是一个简单的文本文件，其内容是一个 sha1 值，表示这个 ref 指向的 object。&lt;br /&gt;&lt;br /&gt;$ find .git/refs&lt;br /&gt;.git/refs&lt;br /&gt;.git/refs/heads&lt;br /&gt;.git/refs/tags&lt;br /&gt;&lt;br /&gt;$ find .git/refs -type f&lt;br /&gt;$&lt;br /&gt;&lt;br /&gt;新建一个 “head reference” (ref 还分好几种，这种指向某个 commit 的叫 head ref，放在 .git/refs/heads/ 目录下)，让它指向最新的 commit：&lt;br /&gt;&lt;br /&gt;echo &amp;#8220;29c0bd0cd9084ad30e0eaca38632500d700d6644&amp;#8221; &amp;gt; .git/refs/heads/master&lt;br /&gt;&lt;br /&gt;这样就用这个 ref 指代其 sha1 值了：&lt;br /&gt;&lt;br /&gt;$ git log &amp;#8211;pretty=oneline master&lt;br /&gt;29c0bd0cd9084ad30e0eaca38632500d700d6644 third commit&lt;br /&gt;b951b414a680c16e48c095a080b435874a5da79e second commit&lt;br /&gt;9fa147d9147f7dbbfa641ebe2992a336bc1a4c93 first commit&lt;br /&gt;&lt;br /&gt;git 不推荐手动修改 ref 文件。可以使用 update-ref 命令：&lt;br /&gt;&lt;br /&gt;$ git update-ref refs/heads/master 29c0bd0cd9084ad30e0eaca38632500d700d6644&lt;br /&gt;&lt;br /&gt;这其实就是 git 里的 branch，一个很简单的指向某个 commit 的指针，或者说 ref。&lt;br /&gt;&lt;br /&gt;用 update-ref 创建一个新 branch：&lt;br /&gt;&lt;br /&gt;$ git update-ref refs/heads/test b951b414a&lt;br /&gt;&lt;br /&gt;$ git log &amp;#8211;pretty=oneline test&lt;br /&gt;b951b414a680c16e48c095a080b435874a5da79e second commit&lt;br /&gt;9fa147d9147f7dbbfa641ebe2992a336bc1a4c93 first commit&lt;br /&gt;&lt;br /&gt;repo 现在的结构：&lt;br /&gt;&lt;br /&gt;并且可以使用 git branch 了，已经有了两个分支：&lt;br /&gt;&lt;br /&gt;$ git branch&lt;br /&gt;* master&lt;br /&gt;&amp;nbsp;test&lt;br /&gt;&lt;br /&gt;在创建新分支的时候，git 仅仅是创建了一个简单的 ref，把新分支名与指定的 commit 联系起来。所以创建分支是个非常 cheap 的。&lt;br /&gt;&lt;br /&gt;那么 merge 分支呢？&lt;br /&gt;&lt;br /&gt;1). git 拿到要进行合并的分支，找到它们所代表的 sha1 值，&lt;br /&gt;2). 读取这两个 sha1 值所表示的 commit object，&lt;br /&gt;3). 读取这两个 commit 对应的 tree object。&lt;br /&gt;4). 创建新 tree。把这两个 tree 合并到一块，产生一个新的 tree (以及可能的新的 blob)&lt;br /&gt;5). 创建 merge commit。把这个 tree 提交为新的 commit，就是最后的 merge commit。merge commit&amp;nbsp; 有多个 parent。&lt;br /&gt;&lt;br /&gt;8. HEAD&lt;br /&gt;&lt;br /&gt;git 怎么知道当前的最新 commit 呢？或者说怎么知道当前所在的分支？&lt;br /&gt;&lt;br /&gt;HEAD 文件用来记录当前的分支。HEAD 也是一个 ref，但是它称作一个 symbolic ref，因为 HEAD 文件里不是包含 sha1 值，而是指向另外一个 ref (refs 目录里的一个文件)。&lt;br /&gt;&lt;br /&gt;$ cat .git/HEAD ref: refs/heads/master&lt;br /&gt;&lt;br /&gt;执行 git checkout &amp;lt;branch&amp;gt; 的时候，git 就会更新 HEAD 文件，切换到新分支。&lt;br /&gt;&lt;br /&gt;执行 git commit 的时候，新创建的 commit object 的 parent 就是 HEAD 所指向的那个 commit。&lt;br /&gt;&lt;br /&gt;可以使用 git symbolic-ref 来读取或修改 HEAD 这种 symbolic ref：&lt;br /&gt;&lt;br /&gt;$ git symbolic-ref HEAD&lt;br /&gt;refs/heads/master&lt;br /&gt;&lt;br /&gt;$ git symbolic-ref HEAD refs/heads/test&lt;br /&gt;$ cat .git/HEAD&lt;br /&gt;ref: refs/heads/test&lt;br /&gt;&lt;br /&gt;9. 不讲&lt;br /&gt;&lt;br /&gt;tags, remotes&lt;br /&gt;&lt;br /&gt;10. 资料&lt;br /&gt;&lt;br /&gt;本文所有内容来自 Pro Git 第 9 章，Git Internals, http://progit.org/book/ch9-0.html。&lt;br /&gt;&lt;br /&gt;其他资料：&lt;br /&gt;&lt;br /&gt;git 手册的 Hack git 那一章，http://schacon.github.com/git/user-manual.html#hacking-git 。尤其是其中提到的 git 的第一个 commit:&lt;br /&gt;&lt;br /&gt;$ git checkout e83c5163&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/vxr7TWRjvDs" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[gnome3]]></title>
    <link href="http://blog.zhangsen.org/2012/04/gnome3.html" />
    <updated>2012-04-17T20:53:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/04/gnome3</id>
    <content type="html">&lt;div class='post'&gt;
gnome3 大多数时候还是比较顺手的。不顺手的地方基本也能找到相应的插件。&lt;br /&gt;&lt;br /&gt;1. alt-tab 把窗口都组合到一块去，这个比较恶。幸好有一些插件，比如 &lt;a href="https://extensions.gnome.org/extension/38/windows-alt-tab/"&gt;https://extensions.gnome.org/extension/38/windows-alt-tab/&lt;/a&gt; 。能恢复到原来的样子。win7 在任务栏上把窗口也组合到一块，也很烦人，但是起码 alt-tab 是正常的。(而且人家有配置选项好吧？）&lt;br /&gt;&lt;br /&gt;2. 关机按钮。这个就不多说了，相应的插件目前在 https://extensions.gnome.org 上排第一位。(&lt;a href="https://extensions.gnome.org/extension/5/alternative-status-menu/"&gt;https://extensions.gnome.org/extension/5/alternative-status-menu/&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;3. 现在的网络管理简直就是个鸡肋，想配 VPN 都没地方找。不过幸好，还可以从命令行运行原来的：&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$ nm-connection-editor&lt;/div&gt;&lt;br /&gt;然后就可以照常导入 vpnc 的配置文件了，等等。&lt;br /&gt;&lt;br /&gt;最后再强调一下，gnome3 大多数时候还是比较顺手的 :) 确实能让人感觉更专注，支持插件也是个很棒的设计。&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/TyEEEiNWlQ4" height="1" width="1"/&gt;</content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[kindle and wifi]]></title>
    <link href="http://blog.zhangsen.org/2012/04/kindle-and-wifi.html" />
    <updated>2012-04-16T20:17:00+08:00</updated>
    <id>http://blog.zhangsen.org/2012/04/kindle-and-wifi</id>
    <content type="html">&lt;div class='post'&gt;
The Kindle was designed in the USA and so uses only the US Wi-Fi channels one to 11&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.pcpro.co.uk/realworld/370147/why-your-kindle-wont-connect-to-wi-fi"&gt;http://www.pcpro.co.uk/realworld/370147/why-your-kindle-wont-connect-to-wi-fi&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;怪不得我的 kindle 死活连不上 wifi。只好把自动扫描信道关了，选个 11 以内的。&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/98Vnm3n8MRc" height="1" width="1"/&gt;</content>
  </entry>
  
</feed>
