<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Log4D]]></title>
  <link href="http://log4d.com/atom.xml" rel="self"/>
  <link href="http://log4d.com/"/>
  <updated>2012-05-19T18:35:37+08:00</updated>
  <id>http://log4d.com/</id>
  <author>
    <name><![CDATA[alswl]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[《写给大家看的设计书》读后感]]></title>
    <link href="http://log4d.com/2012/05/the-non-designers-design-book/"/>
    <updated>2012-05-19T18:10:00+08:00</updated>
    <id>http://log4d.com/2012/05/the-non-designers-design-book</id>
    <content type="html"><![CDATA[<p>我读过两本关于视觉设计的书，一本是<a href="http://book.douban.com/subject/6783748/">《写给程序员的Web设计书》</a>，
这是第二本<a href="http://book.douban.com/subject/3323633/">《写给大家看的设计书》</a>。</p>

<p><img src="http://img3.douban.com/lpic/s6485795.jpg" alt="写给大家看的设计书" /></p>

<p>我对前者的评价是「作者花了大约25%的篇幅来讲述设计理念和方法，这也是我真正想看的部分。
本来想从书中获取更多布局、色彩、字体的内容，发现还是太少了。图灵系的书翻译不错。」</p>

<p>相对应的，《写给大家看的设计书》是我真心想看的设计入门书。作者的文字功底好，经验丰富，
范例适合，取材广泛，总之，是不可多得的一本好书。</p>

<!--more-->


<p>书中提到了设计四大原则：亲密性 / 对齐 / 重复 / 对比。依靠这四个原则，
就可以设计出效果不错的出版物（包括书籍、文档、幻灯片、网页等等）</p>

<ul>
<li><p>对比（Contrast）：对比的基本思想是，要避免页面上的元素过于相似，如果元素
（字体、颜色、大小、线宽、形状、空间等）不相同，那就干脆让它们截然不同。
要让页面引人注目，对比通常是最重要的一个因素，正是它能使读者首先看到这个页面。</p></li>
<li><p>重复（Repetition）：让设计中的视觉要素在整个作品中重复出现。
可以重复颜色、形状、材质、空间关系、线宽、字体、大小和图片，等等。
这样依赖，既能增加条理性，还可以加强统一性。</p></li>
<li><p>对齐（Alignment）：任何东西都不能在页面上随意安放。
每个元素都应当与页面的另一个元素有某种视觉联系。这样能建立一种清晰、
精巧而且清爽的外观。</p></li>
<li><p>亲密性（Proximity）：彼此相关的项应当靠近，归组在一起。
如果多个项相互之间存在很近的亲密性，它们就会成为一个视觉单元，
而不是多个孤立的元素。这有助于组织信息，减少混乱，为读者提供清晰的结构。</p></li>
</ul>


<p>除了设计的四大原则，书中还花费 1/3 的篇幅介绍西文字体，
看完可以对字体有一些初步认识。唯一遗憾的是，中文字体属于 CJK 体系，
书中没有介绍。</p>

<p>西文字体主要分</p>

<ul>
<li>Oldstyle</li>
<li>Modern</li>
<li>Slab serif</li>
<li>Sans serif</li>
<li>Script</li>
<li>Decorative</li>
</ul>


<p>我认为做产品的、做前端的，或者对艺术和美感兴趣的（比如我），都应该读一读这本书。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[关于 NetworkManager / PolicyKit / ConsoleKit 的那些屌事]]></title>
    <link href="http://log4d.com/2012/05/networkmanager-policykit-consolekit/"/>
    <updated>2012-05-17T09:07:00+08:00</updated>
    <id>http://log4d.com/2012/05/networkmanager-policykit-consolekit</id>
    <content type="html"><![CDATA[<p>在使用 Awesome 的过程中，我又遇到了一个老问题「NetworkManager 在非 Gnome
环境启动后，会无法 添加 / 删除 / 编辑 无线连接」。明眼人一看就知道，
这是权限的问题。</p>

<h2>问题描述</h2>

<p>我的环境是 <strong>ArchLinux / xmonad 0.10 / awesome v3.4.11 / GDM 3.4.1 / NetworkManager 0.9.4.0</strong>，
下面我用 awesome 做示例，其他非 Gnome WM 也应该是类似配置。</p>

<p>我的 WM 启动流程是：
通过 GDM 启动 xmonad / awesome，启动 xsession 是 <code>/usr/share/xsessions/awesome.desktop</code>，
内容如下</p>

<!--more-->




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ini'><span class='line'><span class="k">[Desktop Entry]</span>
</span><span class='line'><span class="na">Name</span><span class="o">=</span><span class="s">Awesome</span>
</span><span class='line'><span class="na">Comment</span><span class="o">=</span><span class="s">This session logs you into Awesome</span>
</span><span class='line'><span class="na">Type</span><span class="o">=</span><span class="s">Application</span>
</span><span class='line'><span class="na">Exec</span><span class="o">=</span><span class="s">ck-launch-session dbus-launch $HOME/.start-session.sh awesome</span>
</span><span class='line'><span class="na">TryExec</span><span class="o">=</span><span class="s">/usr/bin/awesome</span>
</span></code></pre></td></tr></table></div></figure>


<p><code>$HOME/.start-session.sh</code> 中的作用是启动 <strong>nm-applet</strong> 和 <strong>exec awesome</strong>。</p>

<p>启动之后的情况是 NetworkManager 无线 编辑/删除 按钮变灰无法点击，或者可以点击，
但是会发生 <strong>insufficient privileges</strong> 错误。</p>

<p><img src="http://upload.log4d.com/2012/05/insufficient-privileges.png" alt="insufficient privileges" /></p>

<h2>问题原因</h2>

<p>这个问题是由 PolicyKit 和 ConsoleKit 启动不当引起的。</p>

<p>PolicyKit 是：</p>

<blockquote><p>PolicyKit allows fine-tuned capabilities in desktop enviroment. Traditionally only privilaged user (root) was allowed to configure network. However while in server enviroment it is reasonable assumption it would be too limiting to not allowed to connect to hotspot on laptop. Still however you may not want to give full privilages to this person (like installing programs) or you want to limit options for some people (for example on your children laptops only &#8216;trusted&#8217; networks with parential filters can be used). As far as I remember it works like:</p>

<ul>
<li>Program send message to daemon via dbus about action</li>
<li>Daemon uses PolicyKit libraries/configuration (in fact PolicyKit daemon) to determine if user is allowed to perform action. It may happen that the certain confition must be fullfilled (like entering password or hardware access).</li>
<li>Deamon performs action according to it (returns auth error or perform action)</li>
</ul>
</blockquote>

<p>ConsoleKit 是：</p>

<blockquote><p>In short consolekit is service which tracks user sessions (i.e. where user is logged in). It allows switching users without logging out [many user can be logged in on the same hardware at the same time with one user active]. It is also used to check if session is &#8220;local&#8221; i.e. if user have direct access to hardware (which may be considered more secure then remote access).</p></blockquote>

<p>参考：<a href="http://unix.stackexchange.com/questions/5220/what-are-consolekit-and-policykit-how-do-they-work">What are ConsoleKit and PolicyKit? How do they work?</a></p>

<p>所以简而言之，ConsoleKit 是用来管理用户会话的，PolicyKit 是用来处理用户申请特殊权限的，
他们两个经常工作在一起。</p>

<p>有个 PolicyKit 认证 API 教程可以一看：</p>

<ul>
<li><a href="http://www.kissuki.com/blog/2009/03/10/policykit/">使用 PolicyKit 进行身份认证（上）</a></li>
<li><a href="http://www.kissuki.com/blog/2009/03/12/policykit/">使用 PolicyKit 进行身份认证（中）</a></li>
<li><a href="http://www.kissuki.com/blog/2009/03/13/policykit/">使用 PolicyKit 进行身份认证（下）</a></li>
</ul>


<p>我的这个问题就是由于 PolicyKit 无法正确授权引起的。</p>

<h2>问题解决</h2>

<p>我开始吭次吭次的 Google，一会就找到了 Arch Wiki 中 <a href="https://wiki.archlinux.org/index.php/NetworkManager#Set_up_PolicyKit_permissions">NetworkManager</a> 的解决办法：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">exec </span>ck-launch-session dbus-launch wm
</span></code></pre></td></tr></table></div></figure>


<p>写的很清楚，使用 <strong>ck-launch-session</strong> 和 <strong>dbus-launch</strong> 来加载 WM。但是我已经使用
<code>ck-launch-session</code> 来启动 WM 了。</p>

<p>随后我把怀疑的目光放到 <code>/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1</code>
这个程序给系统提供 PolicyKit 权限认证，请求时候会让用户输入密码，如下图：</p>

<p><img src="http://upload.log4d.com/2012/05/policykit-agent.png" alt="PolicyKit Agent" /></p>

<p>可惜还是不行。</p>

<p>我甚至还参考<a href="http://blog.san-ss.com.ar/2011/03/using-gnome-keyring-in-xmonad.html">Using gnome keyring in xmonad</a>
试图手工建立一个 Gnome Keyring。事实证明，Gnome Keyring 和这个问题无关。</p>

<p>最后，我用 <code>ck-list-sessions</code> 命令查看运行的用户 Session，发现同时运行着两个，
一个处于 <code>Active</code>，一个不处于 <code>Active</code>，这下真相大白了：GDM 启动时候会自己启动
<code>ck-launch-session</code>，不用自己手动启动，否则会造成两个会话而无法正确授权。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>Session2:
</span><span class='line'>  unix-user <span class="o">=</span> <span class="s1">&#39;1000&#39;</span>
</span><span class='line'>  <span class="nv">realname</span> <span class="o">=</span> <span class="s1">&#39;Jason Ti&#39;</span>
</span><span class='line'>  <span class="nv">seat</span> <span class="o">=</span> <span class="s1">&#39;Seat1&#39;</span>
</span><span class='line'>  session-type <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span><span class='line'>  <span class="nv">active</span> <span class="o">=</span> TRUE
</span><span class='line'>  x11-display <span class="o">=</span> <span class="s1">&#39;:0&#39;</span>
</span><span class='line'>  x11-display-device <span class="o">=</span> <span class="s1">&#39;/dev/tty7&#39;</span>
</span><span class='line'>  display-device <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span><span class='line'>  remote-host-name <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span><span class='line'>  is-local <span class="o">=</span> TRUE
</span><span class='line'>  on-since <span class="o">=</span> <span class="s1">&#39;2012-05-17T00:54:31.706019Z&#39;</span>
</span><span class='line'>  login-session-id <span class="o">=</span> <span class="s1">&#39;2&#39;</span>
</span><span class='line'>Session3:
</span><span class='line'>  unix-user <span class="o">=</span> <span class="s1">&#39;1000&#39;</span>
</span><span class='line'>  <span class="nv">realname</span> <span class="o">=</span> <span class="s1">&#39;Jason Ti&#39;</span>
</span><span class='line'>  <span class="nv">seat</span> <span class="o">=</span> <span class="s1">&#39;Seat1&#39;</span>
</span><span class='line'>  session-type <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span><span class='line'>  <span class="nv">active</span> <span class="o">=</span> False
</span><span class='line'>  x11-display <span class="o">=</span> <span class="s1">&#39;:0&#39;</span>
</span><span class='line'>  x11-display-device <span class="o">=</span> <span class="s1">&#39;/dev/tty7&#39;</span>
</span><span class='line'>  display-device <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span><span class='line'>  remote-host-name <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span><span class='line'>  is-local <span class="o">=</span> TRUE
</span><span class='line'>  on-since <span class="o">=</span> <span class="s1">&#39;2012-05-17T00:54:33.3465302Z&#39;</span>
</span><span class='line'>  login-session-id <span class="o">=</span> <span class="s1">&#39;2&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>修正 <code>/usr/share/xsessions/awesome.desktop</code> 如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ini'><span class='line'><span class="k">[Desktop Entry]</span>
</span><span class='line'><span class="na">Name</span><span class="o">=</span><span class="s">Awesome</span>
</span><span class='line'><span class="na">Comment</span><span class="o">=</span><span class="s">This session logs you into Awesome</span>
</span><span class='line'><span class="na">Type</span><span class="o">=</span><span class="s">Application</span>
</span><span class='line'><span class="na">Exec</span><span class="o">=</span><span class="s">$HOME/.start-session.sh awesome</span>
</span><span class='line'><span class="na">TryExec</span><span class="o">=</span><span class="s">/usr/bin/awesome</span>
</span></code></pre></td></tr></table></div></figure>


<p>事实上，在启动完 GDM 还没进入 WM 之前，<code>Ctrl+Alt+F1</code> 切换到命令行下面，查看进程会发现</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ini'><span class='line'><span class="err">root</span>       <span class="err">637</span>     <span class="err">1</span>  <span class="err">0</span> <span class="err">08:44</span> <span class="err">?</span>        <span class="err">00:00:00</span> <span class="err">/usr/lib/polkit-1/polkitd</span> <span class="err">--no-debug</span>
</span><span class='line'><span class="err">root</span>      <span class="err">1072</span>     <span class="err">1</span>  <span class="err">0</span> <span class="err">08:44</span> <span class="err">?</span>        <span class="err">00:00:00</span> <span class="err">/usr/sbin/console-kit-daemon</span> <span class="err">--no-daemon</span>
</span><span class='line'><span class="err">rtkit</span>     <span class="err">1260</span>     <span class="err">1</span>  <span class="err">0</span> <span class="err">08:45</span> <span class="err">?</span>        <span class="err">00:00:00</span> <span class="err">/usr/lib/rtkit-daemon</span>
</span></code></pre></td></tr></table></div></figure>


<p>果不其然，PolicyKit 和 ConsoleKit 已经在运行了。</p>

<p>实测 Awesome / Xmonad 已经可以正常授权 NetworkManager 来编辑无线了。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用独立图床子域名]]></title>
    <link href="http://log4d.com/2012/05/image-host/"/>
    <updated>2012-05-09T16:21:00+08:00</updated>
    <id>http://log4d.com/2012/05/image-host</id>
    <content type="html"><![CDATA[<p>最近在将 Wordpres 切换到 OctoPress，顺便将图片统一放到<a href="http://upload.log4d.com">Upload4D</a>管理。</p>

<p>我挑选图床管理程序有下面几个需求，需求由强到弱排列：</p>

<ul>
<li>开源</li>
<li>简单</li>
<li>不需数据库支持</li>
<li>支持分目录</li>
<li>允许上传图片</li>
<li>支持后台直接操作文件</li>
<li>支持用户管理，不允许其他人上传</li>
<li>页面美观</li>
<li>不要生成缩略图等文件</li>
<li>软件持续更新</li>
</ul>


<p>于是我踏上了「考古之旅」，先后试用了 MiniGal Nano / MG2 /
CF Image Host Script / minishowcase 等等图床软件，评测记录如下。</p>

<!--more-->


<h2>参赛选手</h2>

<h3><a href="http://www.minigal.dk/minigal-nano.html">MiniGal Nano</a></h3>

<p><img src="http://upload.log4d.com/2012/05/mg-nano.png" title="MiniGal Nano" alt="MG Nano" /></p>

<ul>
<li>没有上传功能</li>
<li>没有后台管理功能</li>
<li>2010年最后更新</li>
</ul>


<h3><a href="http://www.minigal.dk/mg2.html">MG2</a></h3>

<p><img src="http://upload.log4d.com/2012/05/mg2-front.png" alt="MG2 前台" />
<img src="http://upload.log4d.com/2012/05/mg2-admin.png" alt="MG2 管理界面" /></p>

<ul>
<li>假目录，其实所有照片在同一目录下面</li>
<li>界面丑</li>
<li>09年更新</li>
</ul>


<h3><a href="http://meiu.cn/">美优网 Meiu Studio|php相册系统</a></h3>

<ul>
<li>国产</li>
<li>需要 MySQL</li>
</ul>


<h3><a href="http://www.codefuture.co.uk/projects/imagehost/">CF Image Hosting Script v1.4.2</a></h3>

<p><img src="http://upload.log4d.com/2012/05/cf-image-host.png" alt="CF Image Hosting" /></p>

<ul>
<li>据说煎蛋在使用</li>
<li>无法用户控制</li>
<li>无目录</li>
</ul>


<h3><a href="http://minishowcase.net/">Minishowcase</a></h3>

<ul>
<li>没看见上传功能</li>
<li>没看见目录功能</li>
<li>丑</li>
<li>2009年更新</li>
</ul>


<h3><a href="http://qdig.sourceforge.net/">Qdig</a></h3>

<p><img src="http://upload.log4d.com/2012/05/qdig.png" alt="Qdig" /></p>

<ul>
<li>无法上传</li>
<li>丑</li>
<li>2006年更新</li>
</ul>


<h3><a href="http://sourceforge.net/projects/ifoto/">iFoto, CSS-based GD2 photo gallery</a></h3>

<p><img src="http://upload.log4d.com/2012/05/ifoto.png" alt="iFoto" /></p>

<ul>
<li>无法上传</li>
<li>丑</li>
<li>2006年更新</li>
</ul>


<h3><a href="http://encode-explorer.siineiolekala.net/">Encode Explorer</a></h3>

<p><img src="http://upload.log4d.com/2012/05/encode-explorer.png" alt="Encode Explorer" /></p>

<ul>
<li>这其实是一个文件管理器</li>
<li>支持预览</li>
<li>不支持多文件上传</li>
<li>其他要求全部达到</li>
</ul>


<h2>最终选择</h2>

<p>最后，我选择了 Encode Explorer，坑爹吧，获胜者居然是一个文件管理软件，
而不是一个图床软件。</p>

<p>Encode Explorer 是单文件程序，代码一共3k多行，我看了一下，还能支持多语言，
我就加上了中文支持，并且修正了新建目录/新建文件的权限 bug，改为目录755,
文件644，并且这两个模式可以在配置文件修改。</p>

<p>修改之后的 Encode Explorer 可以在
<a href="https://github.com/alswl/encode-explorer">alswl / encode-explorer</a> 找到。</p>

<p>既然已经不单纯是图床了，那我也把以前的一些附件放到这个子域名下，域名也要由
img.log4d.com 改为 upload.log4d.com 。</p>

<p>我用 sed 命令将原来的图片和附件命令批量修改，命令如下
<code>sed -i 's/log4d.com\/wp-content\/uploads/upload.log4d.com/g' ./_posts/*</code>。</p>

<p>ps:今天是我博客独立3周年纪念日，本来想在今天之前把 Wordpress 迁移到
OctoPress，可惜最近太忙，就耽误了。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[《HTML5 实战 WebApp 阅读应用 – Shiu》幻灯片]]></title>
    <link href="http://log4d.com/2012/05/shiu-slide-show/"/>
    <updated>2012-05-05T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/05/shiu-slide-show</id>
    <content type="html"><![CDATA[<p><p>今天去南京 HTML5 沙龙分享了一个幻灯片，讲 Shiu 的开发，同时也分享在这里。</p>
<p><object height="355" id="__sse12809450" width="425"> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=slide-120505055956-phpapp02&amp;stripped_title=html5-webapp-shiu&amp;userName=alswl" /> <param name="allowFullScreen" value="true" /> <param name="allowScriptAccess" value="always" /> <param name="wmode" value="transparent" /> <embed allowfullscreen="true" allowscriptaccess="always" height="355" name="__sse12809450" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=slide-120505055956-phpapp02&amp;stripped_title=html5-webapp-shiu&amp;userName=alswl" type="application/x-shockwave-flash" width="425" wmode="transparent"> </embed> </object></p>
<p>Shiu 的源码托管在 Github，地址是 <a href="https://github.com/alswl/shiu">https://github.com/alswl/shiu</a> 感兴趣可以去看看。</p>
<p>噢，Shiu (/ʃʐy/)，中文音标 (shi r&uuml;))，是一款基于 WebApp 的阅读应用。</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Vim 下模拟 Emacs 键绑定]]></title>
    <link href="http://log4d.com/2012/04/vim-emacs-key-binding/"/>
    <updated>2012-04-20T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/04/vim-emacs-key-binding</id>
    <content type="html"><![CDATA[<p>Vimer 需要 Emacs 键绑定？看上去很蛋疼的需求吧。其实不然，大部分的 Shell / Readline 默认绑定的是 Emacs 键位绑定（处于输入状态下，Emacs 的键位很好用）。Vim 的模式切换很牛逼，但是 Insert 模式下面，只有寥寥几个快捷键，我修改了配置文件，绑定需要的 Emcas 按键到 Vim 中来。</p>

<p>Github 中搜索关键字 Vim Emcas key bind，出来一些结果，不是很完美，我又慢慢调教了几个星期，放出我的 .vimrc。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="s2">&quot; 模拟 Emacs 键绑定</span>
</span><span class='line'><span class="s2">&quot;</span> Move
</span><span class='line'>inoremap &lt;C-a&gt; &lt;Home&gt;
</span><span class='line'>inoremap &lt;C-e&gt; &lt;End&gt;
</span><span class='line'><span class="s2">&quot;inoremap &lt;C-p&gt; &lt;Up&gt;</span>
</span><span class='line'><span class="s2">&quot;</span>inoremap &lt;C-n&gt; &lt;Down&gt;
</span><span class='line'>inoremap &lt;C-b&gt; &lt;Left&gt;
</span><span class='line'>inoremap &lt;C-f&gt; &lt;Right&gt;
</span><span class='line'>inoremap &lt;M-b&gt; &lt;C-o&gt;b
</span><span class='line'>inoremap &lt;M-f&gt; &lt;C-o&gt;w
</span><span class='line'><span class="s2">&quot; Rubout word / line and enter insert mode</span>
</span><span class='line'><span class="s2">&quot;</span> use &lt;Esc&gt;&lt;Right&gt; instead of &lt;C-o&gt;
</span><span class='line'>inoremap &lt;C-w&gt; &lt;Esc&gt;dbcl
</span><span class='line'><span class="err">&quot;</span> delete
</span><span class='line'>inoremap &lt;C-u&gt; &lt;Esc&gt;d0cl
</span><span class='line'>inoremap &lt;C-k&gt; &lt;Esc&gt;&lt;Right&gt;C
</span><span class='line'>inoremap &lt;C-d&gt; &lt;Esc&gt;&lt;Right&gt;s
</span><span class='line'>inoremap &lt;M-d&gt; &lt;C-o&gt;de
</span></code></pre></td></tr></table></div></figure>


<p>需要的朋友请取用，我的 Vim 配置文件和插件在 <a href="https://github.com/alswl/dotfiles">https://github.com/alswl/dotfiles</a> 。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用 Vundle 管理 Vim 插件]]></title>
    <link href="http://log4d.com/2012/04/vundle/"/>
    <updated>2012-04-14T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/04/vundle</id>
    <content type="html"><![CDATA[<p><p>早在这个月初，我就在 Vim 的邮件列表看到了一封关于 Vim 插件管理的 <a href="https://groups.google.com/d/topic/vim-cn/mPES0sNT87Q/discussion">邮件</a>。 才惊呼原来有这么强大的插件可以用来管理我那一坨插件， 今天细细阅读并查了一些资料，便开始配置自己的 Vim。</p>
<h2>几种管理插件</h2>
<p>Vim 的插件管理工具有蛮多，比如：</p>
<ul>
	<li><a href="https://github.com/gmarik/vundle">Vundle</a></li>
	<li><a href="http://www.vim.org/scripts/script.php?script_id=2905">vim-addon-manager</a></li>
	<li><a href="http://www.vim.org/scripts/script.php?script_id=2332">vpathogen.vim</a></li>
	<li><a href="http://www.vim.org/scripts/script.php?script_id=3458">vvundle</a></li>
	<li><a href="https://github.com/c9s/Vimana">vvimana</a></li>
	<li><a href="http://www.douban.com/note/173144456/">一位同学自己写的</a></li>
</ul>
<p>Vim-addon-manager 和 vimana 的对比，参见 <a href="http://yixf.name/2011/10/26/vim%E7%9A%84%E6%8F%92%E4%BB%B6%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/">Vim的插件管理工具</a></p>
<p>我最会选择了 Vundle，通过子目录管理插件，支持 Git 更新。 我其实不太喜欢子目录，觉得目录太多了看着烦，但是考虑到在没有良好的 PKG 包描述文件的前提下，分子目录是一种简单有效（粗暴）的方法。<!--more--></p>
<p>Vundle 通过 git 来对插件进行更新，有三种源可以添加：</p>
<ul>
	<li>github 中 vim-scripts 的项目（这个账号是为 Pathogen 建的，用来建立对 Vim.org 上脚本的镜像）</li>
	<li>github 某个 Vim 插件项目</li>
	<li>某个 git 源</li>
</ul>
<p>以上也是我推荐的选择插件顺序，我认为没有必要去取最新的开发版插件。</p>
<h2>Vundle 安装</h2>
<p>无二话，官方文档的 <a href="https://github.com/gmarik/vundle">Quick Start</a> 写的很详细 ，一句话：</p>
<pre><code>$ git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle
</code></pre>
<p>然后开始配置 .vimrc，我的 <a href="https://github.com/alswl/dotfiles/blob/master/.vimrc">.vimrc</a></p>
<p>重点是配置各种 <code>Bundle</code> 我的配置如下</p>
<pre><code>&quot; My Bundles here:</code></pre></p>

<p>&quot; vim-scripts repos</p>

<p>&quot; Syntax<br />
Bundle &#39;asciidoc.vim&#39;<br />
Bundle &#39;confluencewiki.vim&#39;<br />
Bundle &#39;html5.vim&#39;<br />
Bundle &#39;JavaScript-syntax&#39;<br />
&quot;Bundle &#39;mako.vim&#39;<br />
Bundle &#39;moin.vim&#39;<br />
Bundle &#39;python.vim&#8211;Vasiliev&#39;<br />
Bundle &#39;xml.vim&#39;</p>

<p>&quot; Color</p>

<p>Bundle &#39;desert256.vim&#39;<br />
Bundle &#39;Impact&#39;<br />
Bundle &#39;matrix.vim&#39;<br />
Bundle &#39;vibrantink&#39;<br />
Bundle &#39;vividchalk.vim&#39;</p>

<p>&quot; Ftplugin<br />
Bundle &#39;python_fold&#39;</p>

<p>&quot; Indent<br />
&quot;Bundle &#39;indent/html.vim&#39;<br />
Bundle &#39;IndentAnything&#39;<br />
Bundle &#39;Javascript-Indentation&#39;<br />
Bundle &#39;mako.vim&#8211;Torborg&#39;<br />
Bundle &#39;gg/python.vim&#39;</p>

<p>&quot; Plugin<br />
Bundle &#39;The-NERD-tree&#39;<br />
Bundle &#39;AutoClose&#8211;Alves&#39;<br />
Bundle &#39;auto_mkdir&#39;<br />
Bundle &#39;cecutil&#39;<br />
Bundle &#39;fcitx.vim&#39;<br />
Bundle &#39;FencView.vim&#39;<br />
&quot;Bundle &#39;FuzzyFinder&#39;<br />
Bundle &#39;jsbeautify&#39;<br />
Bundle &#39;L9&#39;<br />
Bundle &#39;Mark&#39;<br />
Bundle &#39;matrix.vim&#39;<br />
Bundle &#39;mru.vim&#39;<br />
Bundle &#39;The-NERD-Commenter&#39;<br />
&quot;Bundle &#39;project.vim&#39;<br />
Bundle &#39;restart.vim&#39;<br />
Bundle &#39;taglist.vim&#39;<br />
&quot;Bundle &#39;templates.vim&#39;<br />
&quot;Bundle &#39;vimim.vim&#39;<br />
Bundle &#39;ZenCoding.vim&#39;<br />
Bundle &#39;css_color.vim&#39;<br />
Bundle &#39;hallettj/jslint.vim&#39;

<p>需要注意的是，Vim 插件名称可能存在重名的情况，这时候就需要在插件后面加上作者的姓氏， 比如 <code>Bundle &#39;Javascript-Indentation&#39;</code> ，而遇到插件名有空格和斜杠的话， 需要将空格和斜杠替换为 <code>-</code> 。</p>
<p>执行 <code>BundleInstall</code> 即可完成安装，如果出现错误提示，多半是名称有问题， 去 github 和 vim.org 搜索一下吧。</p>
<p>更多参考：</p>
<ul>
	<li><a href="http://blog.houqp.me/use-vundle-to-manage-your-plugins/">Vim插件管理利器&mdash;&mdash;Vundle</a></li>
	<li><a href="http://www.cnblogs.com/qiangji/archive/2011/07/31/Vundle.html">使用Vundle 来管理 Vim 插件</a></li>
</ul>
<p>ps：这篇文章第一次尝试使用 Markdown 写博，以前全部是在用 Asciidoc 写（我的 Github 里的 <code>README</code>，都喜欢用 <code>.asciidoc</code>）。貌似是由于 github 带动， Mardown 自 2010 年之后使用人数猛涨，证据在此，上图是 Markdown，下图是 Asciidoc</p>
<p><img alt="Markdown vs Asciidoc" height="260" src="http://log4d.com/wp-content/uploads/2012/04/markdown-asciidoc.png" title="" width="580" /></p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fcitx 配置]]></title>
    <link href="http://log4d.com/2012/04/fcitx-config/"/>
    <updated>2012-04-01T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/04/fcitx-config</id>
    <content type="html"><![CDATA[<p><h2><a name="_fcitx"></a>Fcitx</h2>
<p><img alt="Fcitx" src="http://upload.log4d.com/2012/04/fcitx.png" style="border-width: 0;" /></p>
<p>Fcitx 简介：</p>
<pre>小企鹅中文输入法（Free Chinese Input Toy for X，fcitx）
是一个以 GPL 方式发布的输入法框架， 编写它的目是为桌面环境提供一个灵活的输入方案。</pre></p>

<p>本程序目前可以支持XIM和GTK2，GTK3，QT4的IM Module，可为支持<br />
XIM 的 X 应用程序提供输入服务。 fcitx 的源码包内提供了区位和全/简/双拼，<br />
并支持基于码表的输入法（自带五笔、二笔和仓颉等输入码表）。</p>

<p>您可以从 http://fcitx.googlecode.com 下载最新的发布版本。
<p>当年刚开始使用 Linux 时候，使用的是 iBus，随后发现 Fcitx 这个输入法， 试用了一下就发现自己所需要的 双拼 / 模糊音 / 自定义输入 功能都有提供， 遂转移阵地到 Fcitx。<!--more--></p>
<h2><a name="_fcitx_安装"></a>Fcitx 安装</h2>
<p>大部分发行版软件源都有 Fcitx，Arch 下安装使用命令 <tt>pacman -S fcitx</tt> 即可安装最新版本。Ubuntu 的安装可以参考 <a href="http://wiki.ubuntu.org.cn/Fcitx">http://wiki.ubuntu.org.cn/Fcitx</a> 。</p>
<h2><a name="_fcitx_配置"></a>Fcitx 配置</h2>
<p>详细的配置文档参见 <a href="http://fcitx.github.com/handbook/fcitx.html">http://fcitx.github.com/handbook/fcitx.html</a></p>
<h2><a name="_fcitx_特殊符号"></a>Fcitx 特殊符号</h2>
<p>当我们需要输入特殊符号（数字符号、箭头等等）时候，往往需要去网上搜索对应的 unicode 码，然后拷贝过来。Fcitx 提供一个很方便的功能叫做「特殊符号输入」， 可以定义自己的特殊符号。</p>
<p>在 <tt>/usr/share/fcitx/pinyin/pySym.mb</tt> / <tt>~/.config/fcitx/pinyin/pySym.mb</tt> （ps：我当前版本是4.2.1，所以是这个路径，老版本可能不是这个路径） 中定义需要使用的特殊符号，格式为 <tt>&lt;编码&gt; &lt;符号&gt;</tt> ，比如：</p>
<pre>yinyue ♩
yinyue ♪
yinyue ♫
...</pre>
<p>那么，在 Fcitx 中输入 <tt>yinyue</tt> 就会出现如下候选框</p>
<p><img alt="Fcitx 特殊符号" src="http://upload.log4d.com/2012/04/fcitx-1.png" style="border-width: 0;" /></p>
<p><tt>pySym.mb</tt> 文件中，「编码」和「符号」均不允许出现空格，所以比较适合短小的符号， 而颜文字或者长句不适合在这里出现。颜文字以及其他较长的文字如何快速输入， 就要看 Fcitx 的「快速输入」功能了。</p>
<p>我在这里提供的配置文件包括了常用符号、数字、星座、箭头等等，喜欢可以直接拿去。 ps：我定义的「编码」是全拼，所以可能会混淆正常输入，建议全拼用户将「编码」略做 修改，添加前缀比如 <tt>z</tt> （文档中说 <tt>v</tt> 不能被使用为前缀）。</p>
<p>配置完成之后，使用 <tt>fcitx -r</tt> 重启 Fcitx（使用 Ctrl+5 可以刷新配置文件， 但并不能刷新全部配置文件，建议重启 Fcitx）。 待会配置「快速输入」之后，也需要重启 Fcitx 来让配置文件生效。</p>
<p>我的配置文件 <a href="https://github.com/alswl/fcitx-config/blob/master/pinyin/pySym.mb">fcitx-config / pinyin / pySym.mb</a></p>
<h2><a name="_fcitx_快速输入"></a>Fcitx 快速输入</h2>
<p>Fcitx 的「快速输入」和「特殊符号」很类似，后者管理字符，前者管理自定义语句。</p>
<p>快速输入通过 <tt>；</tt> 按键启用，随后输入相应的「字符组合」，Fcitx 会自动补全。</p>
<p>编码对照文件存放在 <tt>~/.config/fcitx/data/QuickPhrase.mb</tt> 或 <tt>share</tt> 目录下对应的文件中，格式为 <tt>&lt;字符组合&gt; &lt;短语&gt;</tt> ，范例如下</p>
<pre># 颜文字欢呼 （颜文字太需要了，卖个萌什么的太管用了）
yhuanhu (/&ge;▽&le;/)
yhuanhu ヾ(o◕&forall;◕)ﾉ</pre>
<p>在输入法中，键入 <tt>；</tt> 之后再输入 <tt>yhuanhu</tt> 就会出现下面候选框：</p>
<p><img alt="Fcitx 快速输入" src="http://upload.log4d.com/2012/04/fcitx-2.png" style="border-width: 0;" /></p>
<p>从图中可以看出，Fcitx 还自动进行了「字符组合」补全。</p>
<p>我的 <a href="https://github.com/alswl/fcitx-config/blob/master/data/QuickPhrase.mb">fcitx-config / data / QuickPhrase.mb</a> 配置文件按类别收集了一些颜文字，可以直接拿过来使用。</p>
<p>参考链接：</p>
<ul>
	<li><a href="http://zhan.renren.com/fullcirclectt?tagId=163058&amp;checked=true">FCCTT推送特别篇&mdash;&mdash;FCITX输入法快速输入表情</a></li>
	<li><a href="http://site.douban.com/widget/notes/4567539/note/197244464/">颜文字收集整理╰(<strong>&deg;▽&deg;</strong>)</a></li>
</ul>
<h2><a name="_fcitx_中文键位映射"></a>Fcitx 中文键位映射</h2>
<p>很多朋友和我一样，喜欢使用「和」来替换&ldquo;/&rdquo;，至于为什么，知乎有一个回答就解释的很好 <a href="http://www.zhihu.com/question/19589668">为什么大家引用时常用直角引号（「」）而不是弯引号（&ldquo;&rdquo;）？</a></p>
<p>Fcitx 完全可以通过配置中英文键位映射来修改中文状态下面的输入。全局配置文件在 <tt>/usr/share/fcitx/data/punc.mb.zh_CN</tt> 中， 个人配置文件在 <tt>~/.config/fcitx/data/punc.mb/zh_CN</tt> 这个对应位置。</p>
<p>我的配置 <a href="https://github.com/alswl/fcitx-config/blob/master/data/punc.mb.zh_CN">fcitx-config / data / punc.mb.zh_CN</a></p>
<h2><a name="_最后"></a>最后</h2>
<p>关于 Fcitx，有 bug 可以到官网反馈，处理起来效率很高， 感谢作者们给大家带来这么优秀的开源软件。</p>
<p>Update:</p>
<ul>
	<li>2012-03-02 感谢 @Weng Xuetian 指正 <tt>Ctrl + F5</tt> 是错误的，需要使用 <tt>Ctrl + 5</tt> 重载配置。</li>
</ul>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GAE 编程指南读书笔记]]></title>
    <link href="http://log4d.com/2012/03/gae/"/>
    <updated>2012-03-24T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/03/gae</id>
    <content type="html"><![CDATA[<p><p>GAE 和我蛮有缘分，我初学 Python 的其中一个原因就是当时 GAE 刚推出， 当时想法是免费的应用要用起来，要不然就浪费了。随后也假模假样的看文档， 就是没有什么产出。</p>
<p>去年写了一个小应用 <a href="https://github.com/alswl/dbevent2gc">dbevent2gc</a> ， 期间发现 GAE 和普通程序开发的诸多不同，又遭遇 GAE 配额大幅缩水， 写出来的应用运转的不太稳定。在南京图书馆的架上看见这本《GAE 编程指南读书笔记》， 立即借回家仔细阅读。<!--more--></p>
<ul>
	<li>GAE 的简介<br />
		<ul>
			<li>运行时环境 Python / Java</li>
			<li>数据存储 Datastore（实体 / 查询 / 索引 / 事务）</li>
			<li>服务（Memcache / GAccount / 任务队列 / 计划任务）</li>
			<li>工具（SDK / appcfg / dev_appserver / 控制台）</li>
		</ul>
	</li>
	<li>入门（安装 / GAccount / webapp / app.yaml / /_ah/admin / 注册部署 / login:required）</li>
	<li>处理流程：请求 - 前端 - 引用服务器 / 静态文件服务器 - 服务<br />
		<ul>
			<li>配额限制：请求限制 / CPU 限制 / 服务限制 / 部署限制 （最新配额：http://code.google.com/intl/zh-CN/appengine/docs/quotas.html）</li>
		</ul>
	</li>
	<li>数据存储<br />
		<ul>
			<li>GAE 的数据存储方式和传统的 RDBMS 差异比较大，更类似于对象数据库。</li>
			<li>类别 kind / 键 / 键名 key name</li>
			<li>可以通过键来获取和操作对象<br />
				<ul>
					<li><tt>e = db.get(db.Key(&#39;Entity&#39;, &#39;alphabeta&#39;))</tt> / <tt>e = Entity.get(k)</tt></li>
					<li><tt>e = db.get(k)</tt></li>
					<li><tt>e.delete()</tt> / <tt>db.delete(e1, e2)</tt> / <tt>db.delete(k)</tt></li>
				</ul>
			</li>
			<li>Expando 基类可以任意扩展属性，Model 基类则不可。</li>
			<li>GAE 中基本类型与 Python / Java 中基本类型的差异</li>
			<li>多值属性</li>
		</ul>
	</li>
	<li>数据查询<br />
		<ul>
			<li>查询和类别 <tt>db.query()</tt> <tt>query.filter()</tt> <tt>query.order()</tt></li>
			<li>查询和键：查询结果要么返回实体，要么返回键（ <tt>key_only=True</tt> ）</li>
			<li>可以用 GQL 写查询语句，不能写 CUD</li>
			<li>获取结果： <tt>fetch()</tt></li>
		</ul>
	</li>
	<li>索引<br />
		<ul>
			<li>每条查询都需要维护一条索引，在 <tt>index.yaml</tt> 中可以配置</li>
			<li>排序之后的索引查询很快，查询效率和返回结果集有关</li>
			<li>实体的每个属性会自动维护两条索引：升序和降序</li>
			<li>查询时候选取对应的索引进行查询，条件语句可能和排序语句相冲突</li>
			<li>不等于 / IN 操作符将引发一系列变换出的查询</li>
			<li>多值字段的索引：每个值会成为索引中一行 / 实体会因此分散 / 取第一次成功扫描到的行</li>
			<li>多值会引入爆炸索引问题</li>
		</ul>
	</li>
	<li>事务<br />
		<ul>
			<li>通过实体组来控制事务，实体组会在同一块存储区</li>
			<li>GAE 使用乐观锁</li>
			<li>使用 <tt>AModel(parent=p)</tt> 构造祖先，然后通过 <tt>run_in_transation()</tt> 回调事务处理函数</li>
			<li>BigTable 中使用日志+时间戳来跟踪实体的修改，保证数据并发和一致性</li>
			<li>事务更新和索引更新：可能返回的索引结果和实体不一致</li>
		</ul>
	</li>
	<li>Python 数据建模<br />
		<ul>
			<li>声明 / 类型 / 验证（ <tt>validate()</tt> ）</li>
			<li>不编入索引的属性 <tt>indexed=False</tt></li>
			<li>时间类型的自动值</li>
			<li>模型变化带来的维护问题：修改属性类型 / 添加一个必要属性是不向后兼容的。</li>
			<li>关系建模<br />
				<ul>
					<li>db.ReferenceProperty</li>
					<li>collection_name</li>
				</ul>
			</li>
			<li>多对多关系的处理<br />
				<ul>
					<li>键列表方法：使用多值属性</li>
					<li>链接模型方法：相当于中间表概念</li>
				</ul>
			</li>
			<li>模型的继承：通过 <tt>db.PolyModel</tt> 实现多态查询</li>
		</ul>
	</li>
	<li>Memcache<br />
		<ul>
			<li>CRUD</li>
		</ul>
	</li>
	<li>获取 URL 资源<br />
		<ul>
			<li><tt>urlfetch()</tt></li>
		</ul>
	</li>
	<li>RPC 异步请求调用，闭包调用</li>
	<li>邮件和 XMPP<br />
		<ul>
			<li>额，亲用到时候看 Google 官方文档吧～</li>
		</ul>
	</li>
	<li>大批量数据操作和远程访问<br />
		<ul>
			<li><tt>/remote_api</tt></li>
			<li>Bulk Loader 大量数据操作</li>
			<li>远程 shell <tt>remote_api_shell.py app-id</tt></li>
		</ul>
	</li>
	<li>任务队列和计划任务<br />
		<ul>
			<li>队列： <tt>queue.yaml</tt> / 令牌桶</li>
			<li>计划任务： <tt>cron.yaml</tt></li>
			<li>都是通过设定主动触发某个 url</li>
		</ul>
	</li>
	<li>Django<br />
		<ul>
			<li>看 Django 文档吧，亲～</li>
		</ul>
	</li>
	<li>部署<br />
		<ul>
			<li>上传 <tt>appcfg.py update ./clock</tt></li>
			<li>通过 url 使用特定版本： <tt>version-id.latest.app-id.appspot.com</tt></li>
			<li>版本只维护代码，数据库还是同一份</li>
			<li>下载日志 <tt>appcfg.py request_logs clock logs.txt</tt></li>
		</ul>
	</li>
</ul>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[在Python中调试代码]]></title>
    <link href="http://log4d.com/2012/03/python-debug/"/>
    <updated>2012-03-20T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/03/python-debug</id>
    <content type="html"><![CDATA[<p><p>撰写程序时候，需要在调试上面花费不少时间，好的调试工具可以让这个过程如虎添翼， 靠打 log 调试会是一种很痛苦的过程，我总结一下 Pylons 开发的调试技巧。</p>
<p>吐槽：团队开发时候，每个成员需要学习、总结和分享各自的开发技巧， 这样才能自我提升并提高开发效率。这属于团队文化建设，开发是一种艺术创造过程， 绝对不是简单的复制和粘帖。</p>
<h2><a name="_在_python_中调试"></a>在 Python 中调试</h2>
<h3><a name="_pdb"></a>pdb</h3>
<p>在代码中加入下列语句即可启用交互式调试。</p>
<pre class="brush: python;fontsize: 100; first-line: 1; ">import pdb;pdb.set_trace()</pre>
<p>在 pdb 中，可以使用 <tt>h / l / b / n / s / c / j / a / p / ! / q</tt> 这些命令所代表的含义可以通过 <tt>h(elp)</tt> 打印出来。</p>
<p>参考链接：</p>
<ul>
	<li><a href="http://magustest.com/blog/python/use-pdb-debug-python/comment-page-1">用PDB库调试Python程序<!--more--></a></li>
</ul>
<h3><a name="_ipdb"></a>ipdb</h3>
<p>比 pdb 更好用的是 ipdb，需要预先安装 IPython，通过 IPython 可以提供更强的交互功能。</p>
<p>安装 ipdb: <tt>easy_install ipdb</tt> ， 使用方法依然是 <tt>import ipdb;ipdb.set_trace()</tt> 。</p>
<p>ps: 根据我的测试，ipdb 0.61 不能和 ipython 0.91 正常工作， 会报 <tt>ImportError: No module named core.debugger</tt> 错误，请尝试使用 ipython 0.10 或者更新版本。这个错误在 ipdb 官网有 issue 描述 （<a href="https://github.com/gotcha/ipdb/issues/9">link</a>）。</p>
<h3><a name="_使用_embed_python_shell"></a>使用 embed python shell</h3>
<p>除了特定代码的调试，有时候我们还需要在开发一个功能之前进行尝试性代码撰写， 这点在 web 开发时候尤其有用。托 Python 动态语言特性的福，我们可以很方便的使用 Interactivate Shell 进行开发。</p>
<p>在项目的根目录建立一个 Python 脚本，比如 <tt>shell.py</tt> ，其中代码如下：</p>
<pre class="brush: python;fontsize: 100; first-line: 1; ">#!/usr/bin/env python
#coding=utf-8</pre></p>

<p># desc: 这个shell提供Python上下文环境，方便调试<br />
# author: alswl<br />
# date: 2012-03-20</p>

<p>def main():<br />
        # Do something for init here.<br />
    try:<br />
        from IPython.frontend.terminal.embed import InteractiveShellEmbed<br />
        ipshell = InteractiveShellEmbed()<br />
        ipshell()<br />
    except ImportError:<br />
        import code<br />
        pyshell = code.InteractiveConsole(locals=locals())<br />
        pyshell.interact()</p>

<p>if __name__ == &#39;__main__&#39;:<br />
    main()
<p>这段代码先尝试使用 IPython 作为交互 shell，如果没有安装就使用原生 Python 作为 交互 Shell。(强烈建议使用 IPython)。</p>
<p>请在 <tt>main()</tt> 方法开始时候做一些初始化动作，比如载入 webapp 的实例并初始化各路config， 这样就能实现即时代码测试功能，提高开发效率，不用一遍遍地跑流程。</p>
<p>参考链接</p>
<ul>
	<li><a href="http://qixinglu.com/archives/embed_python_shell_in_code">http://qixinglu.com/archives/embed_python_shell_in_code</a> （注意， 这篇文章是2011年的，其中引入 IPython 的 <tt>InteractiveShellEmbed</tt> 的方法已经过期，请参考上面的代码）</li>
</ul>
<h3><a name="_gae_中的_pdb"></a>GAE 中的 pdb</h3>
<p>有一些特定系统，比如 GAE 和 nosetests，他们会重定向 <tt>std:in</tt> 和 <tt>std:out</tt> ， 造成 pdb 无法正确输入和输出，在使用的使用，需要用以下代码做个 hack。</p>
<pre class="brush: python;fontsize: 100; first-line: 1; ">import sys
import pdb
for attr in (&#39;stdin&#39;, &#39;stdout&#39;, &#39;stderr&#39;):
    setattr(sys, attr, getattr(sys, &#39;__%s__&#39; % attr))
pdb.set_trace()</pre>
<h2><a name="_pylons_调试"></a>Pylons 调试</h2>
<p>Paster 的 Shell 交互式调试更显犀利（官方所称杀手级功能）， 可以直接使用 <tt>paster shell dev.ini</tt> 命令启用交互界面，默认会先尝试载入 IPython，不存在就载入原生 Shell。</p>
<p>我当前使用的 Paster 版本为 1.7.5,无法正确识 IPython 0.11及以上版本， 请使用0.9.1或者0.10。</p>
<p>参考链接：</p>
<ul>
	<li><a href="http://wiki.pylonshq.com/pages/viewpage.action?pageId=9011323">How can I use &quot;paster shell&quot; to develop doctest tests?</a></li>
	<li><a href="http://stackoverflow.com/questions/7389388/pylons-paster-shell-does-not-run-in-ipython">stackoverflow 上关于 IPython 版本的问题</a></li>
</ul>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Chrome 独立代理设置]]></title>
    <link href="http://log4d.com/2012/03/chrome-proxy/"/>
    <updated>2012-03-15T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/03/chrome-proxy</id>
    <content type="html"><![CDATA[<p><p>Chrome 在2011年4月份时候，加入了两个新的实验性扩展分支，分别是 Web Navigation Extension API 以及 Proxy Extension API， 通过他们，可以让 Chrome 使用自己独立的代理。</p>
<p>借助这个新功能，我们可以通过 SwitchySharp 使用某个 list 完成部分网址代理。</p>
<p>我的环境： Arch Linux / Chromiun(17.0.963.78) / Proxy SwitchySharp 1.9.38。<!--more--></p>
<h2><a name="_安装_proxy_switchysharp"></a>安装 Proxy SwitchySharp</h2>
<p>由于 <a href="http://code.google.com/p/switchyplus/">SwitchyPlus</a> 停止维护， 因此这里我使用 <a href="http://code.google.com/p/switchysharp/">Proxy SwitchySharp</a>。</p>
<p>Proxy SwitchySharp 介绍如下：</p>
<pre class="brush: plain;fontsize: 100; first-line: 1; ">轻松快捷地管理和切换多个代理设置。基于 &quot;Proxy Switchy!&quot; 和 &quot;SwitchyPlus&quot; 开发。
使用 SwitchySharp 和 GFW List 的图文教程（一次成功，无需重启）  http://is.gd/swap2</pre></p>

<p>**注意！我无法在这个页面回复你的提问。如果有任何故障反馈、求助、建议，请移步项目主页，谢谢！=&gt; http://code.google.com/p/switchysharp/issues/entry</p>

<p>特色：</p>

<p>: 使用 Chrome 代理 API，只修改浏览器代理设置，不修改系统代理设置。<br />
: 支持自动切换模式，可根据 URL 使用不同的代理情景模式。<br />
: 可导入、导出设置。<br />
: 支持在线列表，且能兼容 GFW List  。<br />
: 使用事件监视代理更改，更高效准确。<br />
: 支持改进的快速切换模式，随意在代理之间切换。</p>

<p>为什么我要做这个扩展？ =&gt;<br />
   由于 @gh05tw01f 停止支持和更新 SwitchyPlus 项目，我决定自己对其代码进行修改。<br />
在自己用的同时，本着开源的精神，我也将项目使用 GPL 授权，并上传至商店方便各位使用。</p>

<p>为什么你应该从 SwitchyPlus 转移到 SwitchySharp ？=&gt;<br />
    最重要的原因是， SwitchyPlus 项目已经不再更新，作者也不提供支持。而本项目还在开发过程中，提供支持和更新。<br />
    其次，此扩展支持设置的导入导出，这是 SwitchyPlus 中没有的功能。<br />
    最后，此扩展修复了 SwitchyPlus 中的很多 bug ，且增加了很多激动人心（？）的新功能，如一键切换中使用自动切换模式等。
<p>相关链接：<a href="https://chrome.google.com/webstore/detail/dpplabbmogkhghncfbfdeeokoefdjegm?hl=zh_CN">安装地址</a></p>
<h2><a name="_配置_proxy_switchysharp"></a>配置 Proxy SwitchySharp</h2>
<ul>
	<li>在Chrome地址栏输入 about:flags 找到&ldquo;实验性扩展程序 API&rdquo;启用并重启浏览器。 （新版本可以不勾选）</li>
	<li>勾选在隐身模式下启用。</li>
</ul>
<p>配置主界面如下：</p>
<p><a href="http://upload.log4d.com/2012/03/switchysharp_1.png"> <img alt="SwitchySharp config" height="428" src="http://upload.log4d.com/2012/03/switchysharp_1.png" style="border-width: 0;" width="600" /> </a></p>
<p>其中的 HTTP 代理和端口，根据自己的需要填写。</p>
<p>相关链接： <a href="http://youcan.hourb.com/archives/19">让Chrome浏览器用上独立的代理 | 非诚勿扰</a></p>
<h2><a name="_socks_用户的福音"></a>Socks 用户的福音</h2>
<p>Chrome 是不支持 socks 类型的代理服务器的（<a href="http://code.google.com/p/chromium/issues/detail?id=29914">bug 地址</a>），所以类似 <tt>ssh -D</tt> 建立的 socks 连接都会无法使用，我们需要通过 Privoxy 来将 socks 转换到 http。</p>
<p>Arch Linux 下安装 Privoxy，其他发行版也是类似。</p>
<pre>pacman -S privoxy</pre>
<p>配置 Privoxy，修改 <tt>/etc/privoxy/config</tt> 添加一行：</p>
<pre>forward-socks5 / 127.0.0.1:7070 .</pre>
<p>注意上面的空格和末尾的点。</p>
<p>配置好 Privoxy 后，重启服务，Privoxy 默认在 8118 端口提供服务，可以使用 <tt>127.0.0.1:8118</tt> 来访问代理服务器。</p>
<p>参考链接： * <a href="http://xijie.wordpress.com/2009/12/08/ssh-socks5-%E8%BD%AC-http-3/">ssh socks5 转 http &laquo; 细节的力量</a> * <a href="http://www.privoxy.org/">Privoxy - Home Page</a></p>
<h2><a name="_使用某个_list"></a>使用某个 list</h2>
<p>这事不能说太细，看图说话。</p>
<p><a href="http://upload.log4d.com/2012/03/switchysharp_2.png"> <img alt="SwitchySharp config" height="410" src="http://upload.log4d.com/2012/03/switchysharp_2.png" style="border-width: 0;" width="600" /> </a></p>
<p>注意将某 list 加入切换规则，否则会无法获取 appspot 中的内容。</p>
<p>参考链接：https://autoproxy.org/zh-CN/node/61 （自备梯子）</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[影响力读书笔记]]></title>
    <link href="http://log4d.com/2012/03/influence/"/>
    <updated>2012-03-05T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/03/influence</id>
    <content type="html"><![CDATA[<p><ul>
	<li>本书研究 - 社会心理学 - 顺从心理学。</li>
	<li>日常生活中有大量心理捷径。</li>
	<li>在某个环境下机械地回应某一信息的倾向叫做自动化反应或&ldquo;按一下就播放&rdquo;式反应； 对所有相关信息进行彻底分析后做出反应的倾向，则叫做可控式反应。</li>
</ul>
<p style="text-align: center;"><img alt="Influence" height="146" src="http://img3.douban.com/mpic/s1003546.jpg" width="101" /><a href="http://book.douban.com/subject/1005576/">豆瓣链接</a></p>
<h2><a name="_互惠"></a>1. 互惠</h2>
<ul>
	<li>互惠是人类社会群体的一个独有特征。</li>
	<li>利用小礼物，使目标答应原来会拒绝的请求。</li>
	<li>互惠原理适用于强加的恩惠。</li>
	<li>互惠原理可触发不对等交换。</li>
	<li>违背互惠原理，接受而不试图回报他人善举的人，是不受群体欢迎的。（进化适应器）</li>
	<li>互惠式让步：面对接受的善意，我们感到有义务要偿还。</li>
	<li>拒绝-后撤策略：先提出较大的要求，遭到拒绝之后再提出真正的较小要求。<br />
		<ul>
			<li>责任感</li>
			<li>满意感</li>
		</ul>
	</li>
	<li>如何防范：<br />
		<ul>
			<li>拒绝最初的善意 / 分清楚请求者是否有善意或别有所图</li>
			<li>明辩敌友：善意自然应当得到善意回报，可对销售策略却没有这个必要。<!--more--></li>
		</ul>
	</li>
</ul>
<h2><a name="_承诺和一致"></a>2. 承诺和一致</h2>
<ul>
	<li>人人都有一种言行一致，同时也显得言行一致的愿望。</li>
	<li>人类普遍人为言行一致是基本的人格特征。信仰、言语和行为前后不一的人， 会被堪称是脑筋混乱、表里不一，甚至精神有毛病。另一方面， 言行高度一致大多跟个性坚强、智力出众挂钩，它是逻辑性、稳定性和诚实感的核心。</li>
	<li>每当一个人当中选择了一种立场，便产生了维持它的动机，这样才能显得言行一致。</li>
	<li>言行一致的优势：<br />
		<ul>
			<li>为复杂的现代生活提供一种捷径，被验证过的模式会提供好处</li>
			<li>避免费力的思考。</li>
		</ul>
	</li>
	<li>激活一致性的关键：承诺</li>
	<li>承诺之后甚至会加大顺从度，去做之前小请求毫不相关的事情。</li>
	<li>承诺需要当事人积极、公开、、经过一番努力后自由选择的。<br />
		<ul>
			<li>只有当我们认为外界不存在强大的压力时，我们才会为自己的行为发自内心地负起责任。</li>
			<li>观察当事人，通过他的行为确定一个人自身信仰、价值观和态度</li>
			<li>书面承诺的效果很显著</li>
			<li>公开承诺假话和具有持久的效力，人们会忠于自己的公开决定。</li>
			<li>额外的努力对承诺者的影响力更大。</li>
		</ul>
	</li>
	<li>承诺之后，尽管环境发生了变化，承诺仍然会持续的发挥效用（自己长出腿）。<br />
		<ul>
			<li>这是为了保持内心信仰系统一致。</li>
			<li>抛低球：用甜头引诱，然后再找接口撤销。</li>
		</ul>
	</li>
	<li>公共利益往往是一个很好的承诺点。</li>
	<li>防范引诱性承诺<br />
		<ul>
			<li>肠胃信号</li>
			<li>心灵深处的力量，寻找和信任自己做出反应那一瞬间的乍现灵光。</li>
		</ul>
	</li>
	<li>容易被攻击的弱点<br />
		<ul>
			<li>年龄</li>
			<li>个人主义</li>
		</ul>
	</li>
</ul>
<h2><a name="_社会认同"></a>3. 社会认同</h2>
<ul>
	<li>社会认同原理：在判断何为正确时，我们会根据别人的意见行事。</li>
	<li>推导<br />
		<ul>
			<li>我们对社会认同的反应方式完全是无意识的、条件反射式的，这样一来， 偏颇甚至伪造的证据也能愚弄我们。</li>
			<li>认为一种想法正确的人越多，持有这种想法的人就会觉得它正确。</li>
		</ul>
	</li>
	<li>人越多反而越不安全<br />
		<ul>
			<li>现场有大量旁观者在场时，旁观者伸出援手的可能性最低。</li>
			<li>避免这种情况：指定对象要求救援。</li>
		</ul>
	</li>
	<li>模仿自杀（维特效应）：报道自杀的消息，促使一部分跟自杀者类似的人走向了绝路。</li>
	<li>不确定性的帮助：在人不确定时候，会根据他人的行为指导自己的行为。</li>
	<li>防范：<br />
		<ul>
			<li>那些从众行为往往是赤裸裸伪造的，甚至是可笑的。</li>
			<li>在自己不明白真相时候，取了解真相，避免对集体智慧的极大信任。</li>
		</ul>
	</li>
</ul>
<h2><a name="_喜好"></a>4. 喜好</h2>
<ul>
	<li>社会纽带的影响比对产品本身的好恶强两倍</li>
	<li>喜好的缘由：<br />
		<ul>
			<li>外表：一个人的正面特征能主刀他人看待此人的眼光。 长相好的人更容易在需要帮助的时候获得帮助，在改变听众意见时候也更具有说服力。</li>
			<li>相似性：人们喜欢与自己相似的人，无论是在观点、个性、背景还是生活方式。</li>
			<li>恭维：人们喜欢听人恭维奉承。</li>
			<li>接触和合作：人们对熟悉的人有好感。<br />
				<ul>
					<li>接触带来的熟悉往往能导致更大的好感，但是接触本身蕴含了让人反感的体验， 也许会适得其反。</li>
					<li>在接触时候，努力创造一种&ldquo;我们和他们在为了同一目标而奋斗&rdquo;的氛围， 会提升合作顺利程度。</li>
				</ul>
			</li>
		</ul>
	</li>
	<li>关联性：<br />
		<ul>
			<li>糟糕的消息会让报信人也染上不详。</li>
			<li>流行文化的导向</li>
			<li>新闻、天气和体育的惊人力量：能将成功联系到自己，将自己的公共形象变得光辉。</li>
		</ul>
	</li>
	<li>防范：<br />
		<ul>
			<li>警惕自己的好感度是否超过正常指标</li>
		</ul>
	</li>
</ul>
<h2><a name="_权威"></a>5. 权威</h2>
<ul>
	<li>人往往会听从于专家和上级，难以公然违抗他们。 权威的上级的命令，往往会被无条件的执行，甚至违抗常识、道德和法律。</li>
	<li>权威的象征往往就能降伏我们：<br />
		<ul>
			<li>头衔</li>
			<li>衣着</li>
			<li>身份标识</li>
		</ul>
	</li>
	<li>防范：<br />
		<ul>
			<li>分清楚真正的权威，判断是否是专家</li>
		</ul>
	</li>
</ul>
<h2><a name="_稀缺"></a>6. 稀缺</h2>
<ul>
	<li>物以稀为贵</li>
	<li>对失去某种东西的恐惧，似乎要比对获得同一物品的渴望，更能激发人们的行动力。</li>
	<li>稀缺的特征：数量有限/时间有限。</li>
	<li>逆反心理<br />
		<ul>
			<li>保住既得利益的愿望，是心理逆反理论的核心。</li>
			<li>我们基本可以根据获得一种东西的难易程度，迅速准确地判断它的价值。</li>
			<li>每当东西获取起来比以前难，我们拥有 它的自由受了限制，我们就越发地想要得到它。</li>
			<li>信息审查对受众的影响：人们对封锁的信息更接受、更包容。</li>
		</ul>
	</li>
	<li>创造稀缺的条件：<br />
		<ul>
			<li>新的稀缺：失去比获得带来的震动更大。</li>
			<li>竞争稀缺资源：人们在竞争稀缺资源时候，往往会变得狂热愚昧。</li>
		</ul>
	</li>
	<li>防范：<br />
		<ul>
			<li>警惕在顺从环境下面高涨的情绪</li>
			<li>理解物品的价值来源于本身，而不是稀缺程度。</li>
			<li>避免竞争环境下面的情绪狂热。</li>
		</ul>
	</li>
</ul>
<h2><a name="_新时代环境的影响力"></a>7. 新时代环境的影响力</h2>
<ul>
	<li>我们容易根据孤立的代表性特征做决定，因为现代生活节奏太快，信息太纷杂。</li>
	<li>当代的信息爆炸了。</li>
	<li>我们需要使用捷径来做出快速的相应。</li>
	<li>我们要采取一切合理的方法：抵制、威胁、对峙、谴责、抗议， 来报复刺激我们的捷径反应为目的的虚假信号。</li>
</ul>
<h2><a name="_alswl_的总结"></a>8. alswl 的总结</h2>
<p>关于如何防范，其实只要掌握两点：</p>
<ul>
	<li>避免懒惰，勤加思考（反捷径）</li>
	<li>天上不会掉馅饼（反虚假捷径刺激信号）</li>
</ul>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[给MoinMoin写插件]]></title>
    <link href="http://log4d.com/2012/02/the-write-the-plugins-for-moinmoin/"/>
    <updated>2012-02-10T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/02/the-write-the-plugins-for-moinmoin</id>
    <content type="html"><![CDATA[<p><h2>1. 使用 MoinMoin</h2>
<p>前些日子，我写了一篇<a href="../2011/12/moinmoin-kms">使用MoinMoin作为个人KMS</a> 大赞MoinMoin的各种好处。MoinMoin的其中一个好处是基于GPL的开源， 我们可以方便的给MoinMoin撰写自己的插件（当然也可以去官方的wiki上获取大量现成插件）。</p>
<ul>
	<li><a href="http://moinmo.in/MoinDev">MoinMoin开发者wiki地址</a></li>
	<li><a href="http://docs.moinmo.in/">MoinMoin开发API文档（这个官方wiki居然很少提及）</a></li>
	<li><a href="http://moinmo.in/MoinDev/Translation">MoinMoin的多国语翻译组wiki地址</a></li>
</ul>
<p>我在使用MoinMoin过程中，有一个急迫需要的功能：</p>
<blockquote>
	<p>保存一篇网页时候，要将里面的图片保存到本地，而不是使用外链接方式保存， 因为由于各种不可预测的原因，原始图片数据很有可能丢失或者无法连接。</p>
</blockquote>
<p>这个功能对于将Wiki产品转化为KMS应用非常需要，可惜MoinMoin官方并没有提供， 我也没在MoinMoin的开发者插件库中找到类似功能，就自己写了一个插件image2attach。</p>
<ul>
	<li><a href="http://moinmo.in/MoinMoinExtensions">MoinMoin插件库</a></li>
	<li><a href="http://moinmo.in/ActionMarket/Image2Attach">image2attach在MoinMoin官方Wiki的地址</a></li>
</ul>
<p>现在我分享一下如何写MoinMoin插件，技术大牛可以直接移步官方开发文档， 我这里只是写一些简单的内容，帮助像我一样的同学。</p>
<p>以下内容需要Python编程基础～<!--more--></p>
<h2><a name="_moinmoin_系统结构"></a>2. MoinMoin 系统结构</h2>
<p>MoinMoin的UML图：</p>
<p><img alt="MoinMoin" height="432" src="http://upload.log4d.com/2012/02/MoinMoinArchitecture.png" style="border-width: 0;" width="600" /></p>
<h2><a name="_moinmoin_常用对象"></a>3. MoinMoin 常用对象</h2>
<h3><a name="_request"></a>3.1. request</h3>
<p>这个request和普通jsp/asp中request很类似（实际上这个request就是继承 <a href="http://werkzeug.pocoo.org/">werkzeug</a>的Request）。</p>
<p>除了正常的web request功能，Moin的request还带了Wiki自身的信息。</p>
<ul>
	<li>request.getText # 多国语函数，经常使用 <tt>_ = request.getText</tt> 来简化代码</li>
	<li>request.dicts # 获取定义在页面中的Dict，参见http://moinmo.in/HelpOnDictionaries</li>
	<li>request.groups # 获取权限管理中的组别</li>
	<li>request.user.may # 检查用户权限</li>
</ul>
<h3><a name="_page"></a>3.2. Page</h3>
<p>Page是最常见的类，它代表某个Wiki页面，通过它可以获取某个页面所有信息。 age本身是只读的，如果需要编辑需要使用PageEditor。</p>
<ul>
	<li>Page.exists() # 是否存在</li>
	<li>Page.getRevList() # 版本列表</li>
	<li>Page.current_rev() # 当前版本</li>
	<li>Page.getPagePath() # 存储路径</li>
	<li>Page.get_raw_body() # 获取存储的数据</li>
	<li>Page.send_page() # 发送格式化好页面</li>
</ul>
<h3><a name="_pageeditor"></a>3.3. PageEditor</h3>
<p>上面说到Page是只读的，那当我们需要编辑页面时候，就要用到PageEditor类了。</p>
<ul>
	<li>PageEditor.saveText() # 保存内容</li>
	<li>PageEditor.deletePage() # 删除页面</li>
</ul>
<h3><a name="_attachfile"></a>3.4. AttachFile</h3>
<p>顾名思义，AttachFile用来管理页面附件。</p>
<ul>
	<li>AttachFile.exists() # 检查附件是否存在</li>
	<li>AttachFile.getAttachDir() # 获取附件存放的本地目录</li>
	<li>AttachFile.getAttachUrl() # 获取附件url</li>
</ul>
<h3><a name="_wikiutil"></a>3.5. wikiutil</h3>
<p>wikiutil 是MoinMoin提供的一个帮助类，包含一些常用的小功能。</p>
<ul>
	<li>wikiutil.escape() # html转义</li>
	<li>wikiutil.createTicket() # 生成一串唯一key，用来页面验证</li>
	<li>wikiutil.checkTicket() # 检查ticket</li>
	<li>wikiutil.invoke_extension_function() # 注入脚本类插件</li>
	<li>wikiutil.version2timestamp() # 将MoinMoin时间转换成UNIX时间戳</li>
	<li>wikiutil.timestamp2version() # 参考楼上</li>
	<li>wikiutil.renderText() # 将wiki text转换成html来展现</li>
</ul>
<h3><a name="_user"></a>3.6. user</h3>
<p>用户类，CRUD操作，不解释。</p>
<h3><a name="_formatter"></a>3.7. formatter</h3>
<p>formatter将输出展现类，将wiki text转换为各种预定义的格式。 需要和parser配合使用（两者关系看上去像抽象工厂模式）。</p>
<ul>
	<li>formatter.text() # 格式化为普通文本</li>
	<li>formatter.img() # 格式化为图片</li>
	<li>formatter.number_list() # 格式化为有序列表</li>
	<li>formatter.bullet_list() # 格式化为无序列表</li>
	<li>formatter.listitem() # 格式化为列表项</li>
</ul>
<h3><a name="_parser"></a>3.8. parser</h3>
<p>formatter完成的工作是展现解析后的wiki内容，而负责解析的就是parser了。</p>
<p>流程是这样的：</p>
<pre>wiki -&gt; parser -&gt; formatter</pre>
<p>每一个parser都对应一个或者多个formatter。系统内置的 parser/formatter 有：</p>
<ul>
	<li>docbook</li>
	<li>html</li>
	<li>plain</li>
	<li>python</li>
	<li>rst</li>
	<li>cvs</li>
</ul>
<h2><a name="_moinmoin_运行流程"></a>4. MoinMoin 运行流程</h2>
<ol type="1">
	<li>cgi.py</li>
	<li>通过url获取pagename和action，然后调用对应的Page方法和Action对象<br />
		<ol type="a">
			<li>Page().send_page()创建普通页面</li>
			<li>MoinMoin.action.getHandler()用来获取对应action</li>
		</ol>
	</li>
</ol>
<h2><a name="_moinmoin_开发配置"></a>5. MoinMoin 开发配置</h2>
<h3><a name="_禁用pyc缓存"></a>5.1. 禁用pyc缓存</h3>
<p>MoinMoin 为了提高系统效率，会为 python 文件生成pyc缓存，如果放任它们的话。 每次修改python源码效果都得不到立即体现。所以我们要在开发阶段禁用系统缓存。</p>
<p>在文件 <tt>/usr/lib/python2.7/site-packages/MoinMoin/config/multiconfig.py</tt> 的第815行左右，修改 <tt>options_no_group_name</tt> 中的 <tt>cache</tt> 时间。</p>
<p>当改为0时候，就不使用 <tt>pyc</tt> 缓存，这样就不用重启服务器来清楚缓存了。</p>
<pre>options_no_group_name = {
        # ...
        #&#39;cache&#39;: (600, 30), # cache action is very cheap/efficient
        &#39;cache&#39;: (0, 0), # cache action is very cheap/efficient #XXX alswl
        # ...
}</pre>
<h2><a name="_image2attach_范例"></a>6. image2attach 范例</h2>
<p>image2attach这个插件功能很简单，就是读取wiki文本内容，找出所有图片， 然会将这些图片从互联网上下载到本地，并将文中的图片链接改为MoinMoin的附件链接。</p>
<h3><a name="_创建插件文件"></a>6.1. 创建插件文件</h3>
<p>在 <tt>data/plugin/action/</tt> 目录下创建文件Image2Attach.py。 （请使用大写文件，Moin会自动识别大写开头的Python文件为插件）</p>
<h3><a name="_基本框架"></a>6.2. 基本框架</h3>
<ol type="1">
	<li><tt>execute()</tt> ：hook函数，用来给上层调用，签名必须是 <tt>def execute(pagename, request)</tt></li>
	<li><tt>Class Image2Attach</tt> ：主要类，处理逻辑。<br />
		<ol type="a">
			<li><tt>process() / process_line()</tt> ：处理每行wiki text，会抓取&lt;a&gt;和&lt;img&gt;</li>
			<li><tt>process_transclude() / process_link()</tt> ：分别处理&lt;a&gt; / &lt;img&gt;</li>
			<li><tt>fetch_image()</tt> ：下载图片</li>
			<li><tt>add_attachment()</tt> ：将图片作为附件加入到wiki</li>
			<li><tt>write_file()</tt> ：写入wiki text</li>
		</ol>
	</li>
</ol>
<p>总的来说，开发Moin插件还是比较方便的，官方提供了详尽（但不够顺畅）的教程和 <a href="http://docs.moinmo.in/moin/1.9/">API文档</a>。 我大部分时间在看Moin的API文档， Moin作为一款久经考研的Wiki系统，开放的代码也有很多地方可以学习。</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[再读《重构》]]></title>
    <link href="http://log4d.com/2012/02/refactory/"/>
    <updated>2012-02-05T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/02/refactory</id>
    <content type="html"><![CDATA[<p><p>Martin Fowler 的《<a href="http://book.douban.com/subject/1229923/">重构-改善既有代码的设计</a>》这本书，是我大学老师推荐给我的。 当时我在撰写代码过程中，发现当代码量到某个数量级时候（1000+行）， 就会逐渐失去对代码的控制能力。昆哥推荐了两本书《<a href="http://book.douban.com/subject/1792387/">UML和模式应用</a>》和《重构》这本书。</p>
<p><img align="" alt="refactory" height="139" src="http://img1.douban.com/mpic/s1669771.jpg" width="106" /></p>
<p>这本书是2年前购买的，可惜以我当时的代码感知和撰写能力，看起来颇为吃力。 半途就看得云里雾里而中断了。最近我又重新拾起这本书， 将书中所写的境况与我这两年多来遇到的问题相互印证，才感受到这本经典的力量。<!--more--></p>
<p>Martin 其人：</p>
<pre>ThoughtWorks的首席科学家，当今世界软件开发领域最具影响力的五位大师之一。
他在UML推广普及、领域建模、企业应用开发和敏捷方法等方面建树卓著，被称为软件开发的教父。</pre>
<p>大学时候有段时间我对 Martin 的敏捷非常痴迷。现在对技术的选择没以前那么冲动了， 但是毫不妨碍我对 Martin 的敬仰之情。</p>
<h2><a name="_重构原则"></a>1. 重构原则</h2>
<h3><a name="_重构的定义"></a>1.1. 重构的定义</h3>
<pre>对软件内部结构的一种调整，目的是在不改变&rdquo;软件之可察行为&ldquo;前提下，提高其可理解性，降低其修改成本。</pre></p>

<p>重构就是在代码写好之后改进它的设计。
<ul>
	<li>重构和添加新功能并不冲突，但是当开发者身份在两者之间切换时候，不能混淆在一起。</li>
</ul>
<h3><a name="_重构的意义"></a>1.2. 重构的意义</h3>
<ul>
	<li>优秀设计的根本是：消除重复部分！（DRY = Don&rsquo;t repeat yourself）</li>
	<li>重构让代码更清晰，更容易理解</li>
	<li>清晰的代码可以更方便的找到bug，重构可以写出更强健的代码</li>
	<li>良好的设计可以在长远时间上提高开发速度</li>
</ul>
<h3><a name="_重构的时间"></a>1.3. 重构的时间</h3>
<ul>
	<li>随时进行重构（在我看来，重构更是一种开发的习惯）</li>
	<li>事不过三，代码重复不要超过三次（否则就要&rdquo;抽&ldquo;出来）</li>
	<li>添加功能时候并一一重构（个人理解是，添加新功能之前，分析并重构，从而更方便添加新功能）</li>
	<li>修补错误时</li>
	<li>code review时</li>
</ul>
<h3><a name="_重构和开发进度"></a>1.4. 重构和开发进度</h3>
<p>重构的意义之一也是提高开发进度。杀手锏是&rdquo;不要告诉经理&ldquo;。</p>
<h3><a name="_重构的难题"></a>1.5. 重构的难题</h3>
<ul>
	<li>数据层（数据模型）的变更压力</li>
	<li>修改接口</li>
	<li>那些难以通过重构改变的设计改动</li>
	<li>代码不能运行</li>
	<li>项目期限压力 dead line</li>
</ul>
<h3><a name="_重构与设计"></a>1.6. 重构与设计</h3>
<ul>
	<li>编程不是机械的开发，（软件开发是艺术行为！）</li>
	<li>设计和重构的平衡（预先设计的难度和重构灵活性的平衡）</li>
</ul>
<h3><a name="_重构与性能"></a>1.7. 重构与性能</h3>
<ul>
	<li>重构确实会在短期内降低代码执行效率，但优化阶段是可以调整的，而且调整会更容易。</li>
	<li>提前优化是万恶之源</li>
</ul>
<h3><a name="_那些bad_smell"></a>1.8. 那些Bad Smell</h3>
<ul>
	<li>重复的代码（这才是真正万恶之源，鄙视一切Ctrl+C/P）</li>
	<li>过长函数，会导致责任不明确/难以切割/难以理解等一系列问题</li>
	<li>过大类，职责不明确，垃圾滋生地</li>
	<li>过长参数列（面向对象不是说说而已）</li>
	<li>发散式变化，一个类会响应多种需求而被修改</li>
	<li>散弹式修改（其实就是没有封装变化处，由于一个需求，多处需要被修改）</li>
	<li>依赖情节（一个类对其他类过多的依赖）</li>
	<li>数据泥团（如果数据有意义，就将结构数据变成对象）</li>
	<li>type code，使用Class替代</li>
	<li>switch，少用，考虑多态</li>
	<li>过多平行的类，使用类继承并联起来</li>
	<li>冗余类，去除它</li>
	<li>夸夸其谈的未来性（Matin的文字，侯俊杰的翻译真是&hellip;出彩&hellip;）</li>
	<li>临时值域，封装它</li>
	<li>过度耦合的消息链，使用真正需要的函数和对象，而不要依赖于消息链</li>
	<li>过度的deleate</li>
	<li>过度使用其他类private值域</li>
	<li>重复作用的类</li>
	<li>不完美的类库，（类库老了，使用者也没办法阿）</li>
	<li>纯数据类（类需要行为）</li>
	<li>不纯粹的继承（拒绝父类的接口的类）</li>
	<li>过多注释，注释多了，就说明代码不清楚了</li>
</ul>
<h3><a name="_从测试开始"></a>1.9. 从测试开始</h3>
<p>无测试，无重构，只依赖手工测试，重构时候人会崩溃的。</p>
<ul>
	<li>重构的保真就是自动化测试（如果真的要无聊的手工测试，我也不反对）</li>
	<li>单元测试</li>
	<li>功能测试</li>
</ul>
<h3><a name="_kent_back说"></a>1.10. Kent Back说</h3>
<pre>如果我纯粹为今天工作，明天我将完全无法工作。</pre></p>

<p>间接层的价值：</p>

<p>* 允许逻辑共享<br />
* 分开解释&rdquo;意图&ldquo;和&rdquo;实现&ldquo;<br />
* 将变化加以隔离<br />
* 将条件逻辑加以编码</p>

<p>计算机科学是这样一门学科：它相信所有问题都可以通过一个间接层来解决。 &#8211;Dennis DeBruler
<p>我相信，撰写代码时候不仅仅考虑当下功能，要考虑到有可能出现的情况， 在可能的平衡下面，为将来的扩展做好准备。（也许不仅仅是自己的明天， 还要考虑团队成员的今天工作内容）</p>
<h2><a name="_重构名录"></a>2. 重构名录</h2>
<h3><a name="_重新组织函数"></a>2.1. 重新组织函数</h3>
<dl>
	<dt>Extract Method（提炼函数）</dt>
	<dd>将一段独立的，不依赖上下文的代码组织并独立出来。</dd>
	<dt>Inline Method（将函数内联化）</dt>
	<dd>当函数内部代码简短而容易理解时候，去除这个非必要的间接层。</dd>
	<dt>Inline Temp（将临时变量内联化）</dt>
	<dd>去除只被赋值一次的临时变量。（当有意义时候，应该保留）</dd>
	<dt>Replace Temp with Query（以查询取代临时变量）</dt>
	<dd>将临时变量提取到一个独立函数，并将原来变量引用替换为函数调用。 （我还是担心性能的问题，另外将临时变量限定在一个段落p中，可以避免额外的引用）</dd>
	<dt>Introduce Explainning Variable（引入解释性变量）</dt>
	<dd>将复杂表达式的结果放入临时变量，并用变量名来解释表达式用途。 （自注释代码的表现）</dd>
	<dt>Split Temporary Variable（剖析临时变量）</dt>
	<dd>除了循环变量和临时集合变量，临时变量赋值不能超过一次。</dd>
	<dt>Remove Assignments to Parameters（移除对参数的赋值动作）</dt>
	<dd>不对函数参数进行赋值动作，如果要赋值，创建一个新的临时变量。</dd>
	<dt>Replace Method with Method Object（以函数对象取代函数）</dt>
	<dd>把函数变成对象，再把临时变量变成对象值域。该方法在分解函数时候常用。 （Martin 对小型函数特别迷恋，我认为这个方法更应该用在有逻辑意义的方法上面）</dd>
	<dt>Substitute Algorithm（替换算法）</dt>
	<dd>用更清晰的算法。 （码农都知道）</dd>
</dl>
<h3><a name="_在对象之间搬移特性"></a>2.2. 在对象之间搬移特性</h3>
<p>（面向对象编程原则之一就是职责归属，搬移其实也就意味着职责重新规划）</p>
<dl>
	<dt>Move Method（搬移函数）</dt>
	<dd>将函数移动到被最多次调用的类里面去。 （往往在逻辑意义上，这个函数就应该归属于这个类）</dd>
	<dt>Move Field（搬移值域）</dt>
	<dd>将值域移动到被最多次调用的类里面去。</dd>
	<dt>Extract Class（提炼类）</dt>
	<dd>将开发过程中逐渐变得臃肿的类拆分成数个类，形成清楚的抽象，明确的职责。</dd>
	<dt>Inline Class（将类内联化）</dt>
	<dd>将不再担任足够职责的类搬到另外一个类中，并移除这个原始类。</dd>
	<dt>Hide Delegate（隐藏委托关系）</dt>
	<dd>将直接调用变成间接，在中间添加一层，从而从容面对变更，隔离变化。 （&ldquo;哪里变化，封装哪里&rdquo;这是设计模式的一个经典原则）</dd>
	<dt>Remove Middle Man（移除中间人）</dt>
	<dd>和Hide Delegate相反，移除做了过多简单委托的类。 （应该Hide Delegate需要加入成本，多维护一层，这需要控制一种平衡）</dd>
	<dt>Introduce Foreign Method（引入外加函数）</dt>
	<dd>当类无法进行修改时候，使用静态函数接受这种类型的类实例，</dd>
	<dt>Introduce Local Extenstion（引入本地扩展）</dt>
	<dd>使用子类继承/wrapper类来实现额外的函数。</dd>
</dl>
<h3><a name="_重新组织数据"></a>2.3. 重新组织数据</h3>
<dl>
	<dt>Self Encapsulate Field（自封装值域）</dt>
	<dd>使用getter/setter。 （个人觉得这样很繁琐，.net中的属性方式处理的不错）</dd>
	<dt>Replace Date Value with Object （以对象取代数据值）</dt>
	<dd>当数据项有额外的数据和行为时候，将它变成一个类</dd>
	<dt>Change Value to Reference（将实值对象改为引用对象）</dt>
	<dd>有一些类型，比如日期、星期，不需要保存太多副本。</dd>
	<dt>Change Reference to Value（将引用对象改为实值对象）</dt>
	<dd>和楼上相反的情况，引用会带来复杂的内存分配，在分布式系统中，实值对象特别有用。</dd>
	<dt>Replace Array with Object（以对象取代数组）</dt>
	<dd>不应该将不同的元素存放到数组中，应该使用值域。</dd>
	<dt>Duplicate Observed Data（复制被监视数据）</dt>
	<dd>通过观察者模式，将业务数据和GUI数据进行同步控制</dd>
	<dt>Change Unidirectional Association to Bidirectional（将单向关联改为双向）</dt>
	<dd>使用双向连接，从而能让两个类能互相使用对方特性。</dd>
	<dt>Change Bidirectional Assicuation to Unidirectional（将双向关联改为单向）</dt>
	<dd>当一个类不再需要另外一个类特性时候作修改。</dd>
	<dt>Replace Magic Number with Symbolic Constant（以符号常量/字面常量取代魔法数）</dt>
	<dd>使用有意义的名称，比如pi,gravity。</dd>
	<dt>Encapsulate Field（封装值域）</dt>
	<dd>使用getter/setter。</dd>
	<dt>Encapsulate Collection（封装集群）</dt>
	<dd>避免直接修改容器对象，而是封装出类方法来修改。将变化控制在既有方法内。</dd>
	<dt>Replace Record with Data Class（以数据类取代记录）</dt>
	<dd>将传统编程中的结构体转换为数据类。</dd>
	<dt>Replace Type Code with Class（以类别取代型别码）</dt>
	<dd>使用类型集合类来替换型别码。</dd>
	<dt>Replace Type Code with Subclass（以子类取代型别码）</dt>
	<dd>使用多态来替换型别码，发挥面向对象编程的优势。 （小心处理ORM映射）</dd>
	<dt>Replace Type Code with State/Strategy（以State/Strategy取代型别码）</dt>
	<dd>使用State/Strategy模式来因对type code会发生变化的情况。 将状态类作为父类，再进行继承。</dd>
	<dt>Replace Subclass with Fields（以值域取代子类）</dt>
	<dd>当子类的差异仅仅体现在返回常量数据的函数上时候，进行这样的替换。</dd>
</dl>
<h3><a name="_简化条件表达式"></a>2.4. 简化条件表达式</h3>
<p>简化的核心思想，是将过程式的if/else替换为面向对象的多态。</p>
<dl>
	<dt>Decompose Conditional（分解条件式）</dt>
	<dd>将复杂的条件式提炼为独立函数。</dd>
	<dt>Consolidate Conditional Expression（合并条件式）</dt>
	<dd>将多个条件式判断提炼成一个独立函数。这和上面的分解条件式都需要一个前提： 这几个条件式是要有逻辑关联的。</dd>
	<dt>Consolidate Duplicate Conditional Fragments（合并重复的条件判断）</dt>
	<dd>将所有分支里面都拥有的代码提炼到分支判断之后运行。</dd>
	<dt>Remove Control Flag（移除控制标志）</dt>
	<dd>使用 break/return 取代控制标记。单一出口，多出口。控制标记让程序接口看上去混乱。</dd>
	<dt>Replace Nested Conditional with Guard Clauses（以卫语句取代嵌套条件式）</dt>
	<dd>保留正常情况下面下的顺序执行，提前对非正常情况进行单独检查并返回。 （我更倾向于使用Exception）</dd>
	<dt>Replace Conditional with Polymorphism（以多态取代条件式）</dt>
	<dd>将条件式的每个分支放入一个subclass内覆写函数中，然后将原始函数生命为抽象函数。 （这个方法之前的5种重构手段是代码小手段，引入多态才能充分发挥OOP优势）</dd>
	<dt>Introduce Null Object（引入Null对象）</dt>
	<dd>将无效值替换为null object，从而可以让程序正常运行。 （这好象是一种hack方法，我倾向使用Exception，作者的用以可能是通过Null来减少判断代码）</dd>
	<dt>Introduce Assertion（引入断言）</dt>
	<dd>通过断言来发现程序错误，实际使用中，可以配合 debug mode 使用。</dd>
</dl>
<h3><a name="_简化函数调用"></a>2.5. 简化函数调用</h3>
<dl>
	<dt>Rename Method（重命名函数）</dt>
	<dd>A good name is better than a line of comment.</dd>
	<dt>Add Parameter（添加参数）</dt>
	<dd>你没看错，就是添加参数。 （啊？Matin老师，不带这么水的阿）</dd>
	<dt>Remove Parameter（移除参数）</dt>
	<dd>不要就丢掉。</dd>
	<dt>Separate Query from Modifier（将查询参数和修改参数分离）</dt>
	<dd>将一个即查询状态又修改状态的函数分离开来，职责分离清楚。 （我以前很喜欢写多面手函数～）</dd>
	<dt>Parameterize Method（令函数携带参数）</dt>
	<dd>同一逻辑功能函数，通过重载接受不同参数。而不要建立多个同样的函数。</dd>
	<dt>Replace Parameter with Explicit Methods（以明确函数取代参数）</dt>
	<dd>将单一函数分解为多个函数从而去掉参数，前提是这几个函数的逻辑功能区别较大。</dd>
	<dt>Preserve Whole Object（保持对象完整）</dt>
	<dd>传递完整的对象，取代几个参数的传递。</dd>
	<dt>Replace Parameter with Methods（以函数取代参数）</dt>
	<dd>如果目标函数需要的是几个参数操作的结果，就直接传递这个结果，而不是数个参数。</dd>
	<dt>Introduce Parameter Object(引入参数对象)</dt>
	<dd>当几个参数经常同时出现，就封装他们。 （他们之间往往就有逻辑关系）</dd>
	<dt>Remove Setting Method（移除设值函数）</dt>
	<dd>如果类的某个值域初始化后不再改变，就去掉它的setting方法。 （我理解为原则：&ldquo;减少疑惑，保持唯一&rdquo;）</dd>
	<dt>Hide Method（隐藏某个函数）</dt>
	<dd>使用 private 标记未被其他类调用的方法。</dd>
	<dt>Replace Constructor with Factory Method（以工厂函数取代构造函数）</dt>
	<dd>引入工厂模式。</dd>
	<dt>Encapsulate Downcast（封装向下转型动作）</dt>
	<dd>当知道什么类型时候，将其封装在产生函数里面，减少引用者的困扰。</dd>
	<dt>Replace Error Code with Exception（以异常取代错误码）</dt>
	<dd>如其名。 （关于异常使用的时机，抛出的方式，捕捉的粒度，我困惑了很久。 最后的总结的经验是：在什么层级处理并且仅处理该层级的异常。等有时间详细成文送出）</dd>
	<dt>Replace Exception with Test（以测试取代异常）</dt>
	<dd>异常不是条件判断。</dd>
</dl>
<h3><a name="_处理概括关系"></a>2.6. 处理概括关系</h3>
<p>关于 OOP 继承的那些事儿。</p>
<dl>
	<dt>Pull Up Field（值域上移）</dt>
	<dd>子类重复的值域放到父类去。 （其实还是基于责任归属的问题）</dd>
	<dt>Pull Up Method（函数上移）</dt>
	<dd>子类中重复函数移到父类。</dd>
	<dt>Pull Up Construction Body（构造函数本体上移）</dt>
	<dd>共用的构造函数片段上移。</dd>
	<dt>Push Down Method（函数下移）</dt>
	<dd>将父类中近被某个子类调用的函数下移。</dd>
	<dt>Push Down Field（值域下移）</dt>
	<dd>同上。</dd>
	<dt>Extract Subclass（提炼子类）</dt>
	<dd>当某个类只有部分特性被用到，就需要提取出子类。</dd>
	<dt>Extract Superclass（提炼超类）</dt>
	<dd>和上面相反。</dd>
	<dt>Extract Interface（提炼接口）</dt>
	<dd>将相同的子集提取接口。</dd>
	<dt>Collapse hierarchy（折叠继承体系）</dt>
	<dd>父类和子类并无太大区别时候，合体吧亲。</dd>
	<dt>From Template Mehod（塑造模板函数）</dt>
	<dd>将子类的同功能不同实现函数上移到父类，并在子类提供同名不同实现被调用的子函数。</dd>
	<dt>Replace Inheritance with Delegation（以委托取代继承）</dt>
	<dd>将父类变成一个值域，在调用这个值域的方法。is-a &rarr; has-a （继承太多就会出问题）</dd>
	<dt>Replace Delegation with Inheritance（以继承取代委托）</dt>
	<dd>和上面相反的应用，当子类和父类出现明显的继承关系时候使用。</dd>
</dl>
<h3><a name="_大型重构"></a>2.7. 大型重构</h3>
<p>这一章讲的内容有点高屋建瓴，这里就不概括了，建议读原文。</p>
<ul>
	<li>Tease Apart Inheritance（梳理并分解继承体系）</li>
	<li>Convert Procedural Design to Objects（将过程化设计转化为对象设计）</li>
	<li>Separate Domain from Presentation（将领域和表述/显示分离）</li>
	<li>Extract hierarchy（提炼继承体系）</li>
</ul>
<p>少年，coding时候重构你的代码吧！</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[暗时间读书笔记]]></title>
    <link href="http://log4d.com/2012/01/an-shi-jian/"/>
    <updated>2012-01-15T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/01/an-shi-jian</id>
    <content type="html"><![CDATA[<p><p><a href="http://mindhacks.cn/">pongba</a>的大作《<a href="http://book.douban.com/subject/6709809">暗时间</a>》，讲述效率、习惯、思维，还有一些数学史话和算法，推荐一看。</p>
<p><img alt="" height="432" src="http://img3.douban.com/lpic/s6586365.jpg" width="309" /></p>
<p>ps：我的读书笔记比较水，也许成为摘抄更合适。我习惯这种大纲式的笔记，方便我回想。这里有<a href="http://book.douban.com/review/5012104/">一篇很赞的评论</a>，介绍了三头牛，其中有笑来老师和刘未鹏。<!--more--></p>
<h2><a name="_效率_记忆和学习"></a>1. 效率、记忆和学习</h2>
<ul>
	<li>暗时间<br />
		<ul>
			<li>那些瓶颈较细的能够抓住每一粒时间之沙，虽然啥子总量一样，但相对却拥有更长的生命。</li>
		</ul>
	</li>
	<li>投入时间和效率<br />
		<ul>
			<li>投入时间这个说法本身就是荒唐的，实际投入的是时间和效率的乘积。</li>
			<li>避免工作内容切换带来的上下文时间损耗</li>
			<li>通过锻炼缩短进入状态的能力</li>
			<li>能够迅速进入专注状态，以及能够长期保持专注状态，是高效学习的两个最重要习惯。</li>
		</ul>
	</li>
	<li>设计你自己的进度条<br />
		<ul>
			<li>设计你自己的进度条</li>
			<li>不要过早退出循环<br />
				<ul>
					<li>绝大多数情况下你并不孤单，你遇到的问题早就有人遇到过，你踩过的坑里尽是前人的脚印。</li>
				</ul>
			</li>
			<li>兴趣遍地都是，专注和持之以恒才是真正稀缺的<br />
				<ul>
					<li>性格里面有没有维持兴趣的火种一直燃烧下去的燃料</li>
				</ul>
			</li>
			<li>靠专业技能的陈宫是最具有可复制性的</li>
			<li>反思是让人得以改进自己的最重要思维品质</li>
			<li>一生的知识积累，自学的起码占90%</li>
		</ul>
	</li>
	<li>如何有效的记忆与学习<br />
		<ul>
			<li>最终目的是要在恰当的时候能够想起来去使用</li>
			<li>记忆线索的提取<br />
				<ul>
					<li>知识信息：精细的概念、逻辑、一般的解题原则、通用的解题手法、背景知识、类似的问题</li>
					<li>环境因素：环境、味道、声音</li>
					<li>语言背景</li>
				</ul>
			</li>
			<li>如何记忆<br />
				<ul>
					<li>主动回顾</li>
					<li>创造回忆的机会</li>
					<li>虚拟别人的经历</li>
					<li>抽象和推广</li>
					<li>比较自己的经历</li>
				</ul>
			</li>
		</ul>
	</li>
	<li>学习密度和专注力<br />
		<ul>
			<li>并非靠自制力去强迫不受干扰，真正的效率源自于内心对一个事物的强烈的热忱。</li>
			<li>专注力的意义<br />
				<ul>
					<li>专注力可以让表层意识全功率运作</li>
					<li>专注力可以让潜意识进入一种专注状态，在非工作时间持续发挥作用。</li>
				</ul>
			</li>
			<li>获取专注力<br />
				<ul>
					<li>人在接触一样新事物时候都是极其专注的（小时候的故事）。</li>
					<li>克服焦虑，焦虑会严重影响专注力</li>
					<li>享受困难，保持乐观心态</li>
					<li>GTD，要事第一，让不重要的事情来找自己</li>
				</ul>
			</li>
		</ul>
	</li>
	<li>刘未鹏的学习习惯<br />
		<ul>
			<li>学习和思考<br />
				<ul>
					<li>Google &amp; Wiki</li>
					<li>看书挑剔，只看经典</li>
					<li>做读书笔记</li>
					<li>将思考变成习惯，避免焦虑</li>
					<li>多看心理学与思维的书，因为它们是跨学科的</li>
					<li>学习知识的技巧：它的本质是什么？它的第一原则是什么？它的知识结构是怎样的？</li>
					<li>学习和思考时候常问自己问题<br />
						<ul>
							<li>你的问题到底是什么</li>
							<li>有什么收获</li>
							<li>设想自己正在将东西讲给别人听</li>
							<li>设想讲给一个不懂的人听</li>
							<li>市场反省和注意自己的思维过程</li>
							<li>养成反驳自己的想法的习惯</li>
							<li>问自己，真的理解了么</li>
						</ul>
					</li>
				</ul>
			</li>
			<li>时间和效率<br />
				<ul>
					<li>趁着对一件事情有热情的时候，一股脑儿把万事开头那个最难的阶段熬过去</li>
					<li>重要的事情优先</li>
					<li>重要的事情要营造比较大的时间快来完成</li>
					<li>同时也要善于利用小块时间</li>
					<li>重视知识的本质</li>
					<li>重视提前积累的强大力量（要把眼光多看，就能提前准备）</li>
					<li>抬起头来（停下来，问问自己做的事情是否有意义）</li>
					<li>退订RSS（这个嘛，过滤就好了）</li>
					<li>总结最近得到的新知识</li>
					<li>保持看书（书本的知识质量优于互联网上的知识）</li>
					<li>制定简要的阅读计划</li>
				</ul>
			</li>
			<li>时间和效率2<br />
				<ul>
					<li>根据主体来查阅资料，而不是根据资料来查阅主题</li>
					<li>好资料是根据思考过程来推导，坏资料是上来就写定理公式</li>
					<li>学习一样东西，首先要在大脑中积累充分的疑惑感</li>
					<li>有选择的阅读</li>
					<li>书籍分为两类，一种是知识的，一种是思维的</li>
					<li>看不懂的时候，有可能是几种原因：<br />
						<ul>
							<li>看的不够使劲</li>
							<li>牵扯到了不懂的概念</li>
							<li>作者讲述的顺序不对</li>
						</ul>
					</li>
					<li>在阅读之前就获取书本质量的评估</li>
					<li>如何搜索好书：同作者，Amazon/Douban推荐，提到其他著作的数，别人之作的索引</li>
				</ul>
			</li>
			<li>知识结构<br />
				<ul>
					<li>抓住不变量（本质的知识）</li>
				</ul>
			</li>
			<li>习惯的养成<br />
				<ul>
					<li>人容易珍视自己长期积累的信念</li>
					<li>理智是情感的奴隶</li>
					<li>不自我欺骗，承认养成习惯的难度，并注意观察自己的行为，经常自我认知</li>
				</ul>
			</li>
		</ul>
	</li>
</ul>
<h2><a name="_逃出你的肖申克"></a>2. 逃出你的肖申克</h2>
<ul>
	<li>亲身经历才能明白<br />
		<ul>
			<li>切身体验：心理学上表明，人无法从强度上正确感受到他人痛苦</li>
			<li>别人口中的故事：会受到讲述人自己观念的影响而影响</li>
			<li>为什么：往往他人只讲述how，而不是why</li>
			<li>世界是复杂的：影响的因素太多，未必是别人认为的</li>
			<li>未来是不确定的：&ldquo;你只要&hellip;&hellip;就能&hellip;&hellip;&rdquo;的错觉。只有做好准备，而无万全之策</li>
			<li>别人的道理，自己的事情：知识经验跨越情景转移失败</li>
			<li>认识失调和自我辩护：自我辩护倾向</li>
			<li>失败即成功：自己的失败，也能给予一些信息和帮助</li>
			<li>情绪对照：pass</li>
			<li>天性：进化心理学，理性vs情绪</li>
			<li>习惯</li>
		</ul>
	</li>
	<li>亲身经历未必明白<br />
		<ul>
			<li>很傻很天真的条件反射：遇到失败容易放弃，其实没有好的结果并不代表过程就错了。 判定成功失败从更长远的上来做统计</li>
			<li>认知偏差：将失败归于外界，将成功归于自身</li>
			<li>情绪系统：我们平时的决策强烈依赖情绪系统输出。情绪是决策系统之一，而不应该是全部</li>
		</ul>
	</li>
	<li>不需经历也能明白-理性的力量<br />
		<ul>
			<li>不应该让事实替代我们进行思考和推理，而需要进行社会学习（从别人错误中学习）</li>
			<li>人类最强大的能力之一是归纳和推理（和波利亚解题的归纳/联想相对应）</li>
		</ul>
	</li>
	<li>错觉和偏见<br />
		<ul>
			<li>平凡的解释vs疯狂的解释</li>
			<li>理所当然的错误：人往往无法看到或设想另一种可能性</li>
			<li>打破这种的偏见唯一途径就是开阔视野，积累知识，以及和具有不同知识背景的人讨论</li>
		</ul>
	</li>
	<li>新皮层和原始皮层<br />
		<ul>
			<li>理智vs情绪</li>
		</ul>
	</li>
	<li>理智和情感<br />
		<ul>
			<li>我们的理性大脑非常善于对自己的行为作出立即的，看上去合理的解释。</li>
			<li>思想钢印</li>
			<li>大脑符合用进废退的原理，越经常使用的区域会越来越强大。</li>
			<li>习惯之所以难以改变，就是因为习惯是自我巩固的。</li>
			<li>能够改变既有的习惯，依靠的不是自制力，而是知识。</li>
		</ul>
	</li>
	<li>书写是为了更好的思考</li>
	<li>为什么你从现在开始就应该写博客</li>
	<li>我能与我不能<br />
		<ul>
			<li>我想&rarr;我不能&rarr;我不想</li>
			<li>自利归因</li>
		</ul>
	</li>
	<li>遇到问题为什么应该自己动手<br />
		<ul>
			<li>捷径未必正确，只是小聪明</li>
			<li>问题之外的知识会更多</li>
		</ul>
	</li>
	<li>什么才是你的不可替代性和核心竞争力<br />
		<ul>
			<li>专业领域技能</li>
			<li>跨领域的技能</li>
			<li>学习能力</li>
			<li>性格要素</li>
		</ul>
	</li>
</ul>
<h2><a name="_跟波利亚学解题"></a>3. 跟波利亚学解题</h2>
<ul>
	<li>跟波利亚学解题<br />
		<ul>
			<li>联想<br />
				<ul>
					<li>联想是为了补上从条件到结论、从已知到未知之间缺失的链环</li>
					<li>联想可以将问题向上归约一层，或者将条件往下推导一层</li>
					<li>Working Backward (倒过来解)：将需要求解的问题本身当作条件，再进行推导。</li>
				</ul>
			</li>
			<li>一些思维方法<br />
				<ul>
					<li>时刻不忘未知量：始终知道自己需要什么</li>
					<li>用特例启发思考</li>
					<li>反过来推导：结论往往蕴含丰富的条件</li>
					<li>试错：穷举</li>
					<li>调整题目的条件：通过调整条件，找到条件和结论之间是如何联系的</li>
					<li>求解一个类似的题目：寻求通用的方法</li>
					<li>列出所有可能和问题相关的定理或性质</li>
					<li>考察反面，考察其他所有情况</li>
					<li>将问题泛化，并求解这个泛化的问题</li>
					<li>意识孵化法（即前面提到的，将问题存在潜意识里面）</li>
					<li>烫手山芋法（2B方法）</li>
					<li>让联想更容易发生<br />
						<ul>
							<li>已有知识是双刃剑：提供了解决问题的捷径，同时也是思维的桎梏</li>
							<li>使用抽象将问题泛化，只抓住本质</li>
						</ul>
					</li>
					<li>好题目，坏题目</li>
					<li>思考的习惯：记录<br />
						<ul>
							<li>人的记忆资源是有限的</li>
							<li>将精力集中在某个过程，而不是全部过程上</li>
							<li>记录更能刺激神经兴奋</li>
							<li>记录可以方便的回顾，防止进入思维定势</li>
							<li>方便解题之后整理</li>
						</ul>
					</li>
					<li>练习练习<br />
						<ul>
							<li>将外显记忆转化为内隐记忆</li>
							<li>养成正确思维习惯</li>
							<li>增加领域知识</li>
							<li>帮助养成策略性联想</li>
						</ul>
					</li>
					<li>启发法并不能精准的命中目标，而只能划定一个大致的范围</li>
					<li>总结的意义：在解题过程中寻找一般性的、跨问题的思维思维法则</li>
				</ul>
			</li>
			<li>锤子和钉子<br />
				<ul>
					<li>记住问题是什么</li>
					<li>专注于想要解决的问题</li>
				</ul>
			</li>
			<li>鱼是最后一个看到水的（这章像是赚稿费的，果然是文章集，呵呵）<br />
				<ul>
					<li>Think out of the box</li>
				</ul>
			</li>
			<li>知其所以然<br />
				<ul>
					<li>我们要下蛋的鸡</li>
					<li>两种思维形式<br />
						<ul>
							<li>联想</li>
							<li>演绎&amp;归纳</li>
						</ul>
					</li>
					<li>所以然是什么？什么是问题的价值？<br />
						<ul>
							<li>内隐化：将知识变成本能</li>
							<li>跨情境运用</li>
							<li>对问题解的更多记忆提取线索：通过线索记住这个问题以及解法</li>
							<li>更多的知识：(beyond the question)</li>
							<li>重要分析推理，而不是联想：推理更靠谱</li>
							<li>寻找问题原始出处：那里也许讲的更详细</li>
							<li>整理自己的思路</li>
						</ul>
					</li>
				</ul>
			</li>
			<li>为什么要知其所以然<br />
				<ul>
					<li>更难忘记</li>
					<li>知识结构是树状的，越往上走，需要记忆的节点越少</li>
				</ul>
			</li>
			<li>康托尔、歌德尔、图灵（pass）</li>
			<li>快速排序：让未知世界无机可乘，让答案的任何一个分支都是等概率</li>
			<li>贝叶斯算法：（黑客与画家也提到这个算法）</li>
		</ul>
	</li>
</ul>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[baidu ting下载音乐脚本]]></title>
    <link href="http://log4d.com/2012/01/tingdownload/"/>
    <updated>2012-01-03T00:00:00+08:00</updated>
    <id>http://log4d.com/2012/01/tingdownload</id>
    <content type="html"><![CDATA[<p><p>度娘终于干了一件好事，<a href="http://ting.baidu.com">Baidu Ting</a>上线了， 正版音乐免费下载，类似于<a href="http://www.google.cn/music">谷歌音乐</a>。 关于音乐版权和免费的问题， 有很多问题需要取讨论， 比如说这种商业模式是否对传统唱片业产生冲击又或是有积极影响？ 作为普通消费者，暂时不用考虑这些问题，先享受这些服务好了。</p>
<p>Baidu Ting的音乐质量是128KBps，音质算好，里面的idv3信息也勉强可以，有:</p>
<ul>
	<li>歌名</li>
	<li>歌手</li>
	<li>部分专辑名（偶尔也出现&ldquo;201-8月新歌快递&rdquo;这种比较山寨的字）</li>
	<li>部分唱片封面图片</li>
</ul>
<p>虽然比不上谷歌音乐连歌曲风格都准备好了，但是比杂乱无章的那些音乐mp3要好太多了。</p>
<h2><a name="_自动下载脚本tingdownload"></a>自动下载脚本tingdownload</h2>
<p>早上下了几首音乐，就顺手写了一个脚本，用来批量从Badu Ting下载音乐。</p>
<p>代码在<a href="https://github.com/alswl/tingdownload">github-tingdownload<!--more--></a></p>
<h2><a name="_需要"></a>需要</h2>
<ul>
	<li>Python 2 (仅在Python2.7下测试)</li>
	<li>BeautifulSoup(已包含在目录下)</li>
	<li>simplejson（已包含在目录下)</li>
	<li>一点点Python基础</li>
	<li>Linux/Windows（我在Linux没问题，Windows应该也可以）</li>
</ul>
<h2><a name="_使用方法"></a>使用方法</h2>
<p>在Shell(命令行)里输入下面随便一个命令，就会在当前目录下面出现 <tt>musics</tt> 文件夹， 里面就有下载好的音乐。</p>
<pre># 使用说明
usage: tingdownload.py [-h] [--input INPUT] [Keyword [Keyword ...]]</pre></p>

<p>A script to download music from ting.baidu.com.</p>

<p>positional arguments:<br />
  Keyword</p>

<p>optional arguments:<br />
  -h, &#8211;help            show this help message and exit<br />
  &#8211;input INPUT, -i INPUT<br />
                        a list file to input musics<pre class="brush: bash;fontsize: 100; first-line: 1; "># 示例
python tingdownload.py 老男孩 #单个文件下载
./tingdownload.py 老男孩 #单个文件下载（给python文件加上可执行权限）
python tingdownload.py 老男孩 Raise\n Me\n Up # 多文件名，如果有空格，请记得加上空格反转&#39;\n&#39;</pre>
<p>批量下载的话，可以准备一个列表文件，每个歌曲名用回车隔开，如下：</p>
<pre>还过得去
不敢太幸福
小情歌
爱情靠不住
我爱我
你可以不用给我答案     金莎
没有这首歌         后弦
        回不去了吗         萧亚轩
        有些事现在不做 一辈子都不会做了  五月天
        第一夫人    张杰</pre>
<p>将这个list文件作为输入传入执行脚本：</p>
<pre>python2.7 tingdownload.py --input ~/music.txt</pre>
<p>运行结果如下，列出四种情况：</p>
<ul>
	<li>下载成功，如果文件已经存在，会跳过</li>
	<li>下载失败，由于网络原因</li>
	<li>下载失败，由于关键词不准确而出现太多结果</li>
	<li>下载失败，没有关键词匹配的结果</li>
</ul>
<pre class="brush: bash;fontsize: 100; first-line: 1; ">█▓▒░alswl@x201█▓▒░ ~/dev/project/python/tingdownload/ ./tingdownload.py 黄昏\ 周传雄 考试什么 --input ~/a.txt
&gt; Start download 黄昏 周传雄...
# Info: File &quot;/home/alswl/dev/project/python/tingdownload/musics/周传雄-黄昏.mp3&quot; exists.
&gt; Start download 考试什么...
# Info: File &quot;/home/alswl/dev/project/python/tingdownload/musics/徐良-考试什么的去死吧.mp3&quot; exists.
&gt; Start download 还过得去...</pre></p>

<p>&gt; Start download 不敢太幸福&#8230;<br />
&gt; Start download 小情歌&#8230;<br />
# Failed: Too more result found for keyword 小情歌.<br />
&gt; Start download 爱情靠不住&#8230;</p>

<p>== Download success (4) ==<br />
黄昏 周传雄<br />
考试什么<br />
还过得去<br />
不敢太幸福</p>

<p>== Download failed for too many result (1) ==<br />
小情歌
<p>Enjoy it.</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[My 2011]]></title>
    <link href="http://log4d.com/2011/12/my-2011/"/>
    <updated>2011-12-31T00:00:00+08:00</updated>
    <id>http://log4d.com/2011/12/my-2011</id>
    <content type="html"><![CDATA[<p><p>这个时间点，办公室里都是同事，想必晚上回家之后，那个零点肯定寂寞空虚冷， 手里夹根烟了。所以趁现在心情还不落寞，把年终小结写了。</p>
<p>每当目光从走过的脚步上扫过，总感觉之前的成绩不够漂亮，可以做的更好。 回顾过去是为了收获更卓越的明天。</p>
<p>2011，从不喜爱的ERP行业抽身，奔赴互联网，作出自己的选择。</p>
<p>我成为了一名Python程序员，并完全转换到Linux环境。</p>
<p>花了两个多月时间独自一个人装修，算是在这个城市扎根下来了。</p>
<p>依然是一个光棍，执着于自己的执念。</p>
<p>要么身体在路上，要么精神在路上，我来细数一下2011年精神的转折点。</p>
<ul>
	<li>走出软件作坊 # 反思DW的工作</li>
	<li>人月神话 # 寻找DW的问题，并尝试解决方案</li>
	<li>黑客与画家</li>
	<li>暗时间</li>
	<li>构建高性能Web站点</li>
	<li>重构</li>
</ul>
<p>新年的愿望有两个：</p>
<ul>
	<li>离梦想更近一步</li>
	<li>找一个靠谱的姑娘，我感觉她需要我，我也需要她了</li>
</ul>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用MoinMoin作为个人KMS]]></title>
    <link href="http://log4d.com/2011/12/moinmoin-kms/"/>
    <updated>2011-12-26T00:00:00+08:00</updated>
    <id>http://log4d.com/2011/12/moinmoin-kms</id>
    <content type="html"><![CDATA[<p><p><a name="preamble"></a></p>
<p>去年9月份时候，我写过一篇《<a href="http://log4d.com/2010/09/my-kms">我所使用的知识管理系统</a>》 来介绍我使用的KMS系统。当时经过我层层筛选之后，我选用了Wiz作为我的KMS。</p>
<p>一年多过去了，Wiz在Windows下面工作的非常不错，Wiz团队里陆续推出了iOS / Android / <a href="http://service.wiz.cn/web/">Web</a>版本。我的Wiz收藏的内容也增加到近1000篇。</p>
<p>此时我遇到了KMS再选型的问题，原因很简单：我全线转换到Linux平台， Wiz不符合我的要求了。</p>
<p>我重新整理一下我要求KMS的特性：</p>
<ul>
	<li>跨平台：Linux / Web / iOS / Android / Windows</li>
	<li>数据保存格式：移植方便，将图片保存到本地</li>
	<li>数据采集方式：支持网络直接拷贝复制</li>
	<li>数据索引：支持分类 + tag</li>
	<li>协同工作：方便的分享机制</li>
	<li>免费</li>
</ul>
<p>经过我历时N月的搜寻筛选，MoinMoin Wiki中标了！<!--more--></p>
<h2><a name="_关于moinmoin"></a>1. 关于MoinMoin</h2>
<p>MoinMoin是使用Python编写的Wiki实现，MoinMoin当前版本1.9。</p>
<p>MoinMoin的优点是：</p>
<ul>
	<li>安装简单;</li>
	<li>支持中文全文检索；</li>
	<li>汉化较好；</li>
	<li>不依赖外界的数据库, 使用纯文本保存, 备份非常容易, 直接复制即可。</li>
	<li>支持从html转换到MoinMoin Wiki格式，纯文本的wiki格式比html来的更纯粹，只保存需要的数据，而不保存冗余的样式，MoinMoin这点做的非常好，支持几乎全部html标记的转换。</li>
</ul>
<h2><a name="_安装moinmoin"></a>2. 安装MoinMoin</h2>
<p>MoinMoin基于Python，因此安装比基于php的MediaWiki麻烦一点。</p>
<p>你也可以参考<a href="http://moinmo.in/HowTo">官方安装指导（英文）</a>，里面有 Ubuntu / CentOS / SuSE 等系统的安装方法。</p>
<h3><a name="_使用moinmoin桌面版"></a>2.1. 使用MoinMoin桌面版（最简单）</h3>
<p>好在有MoinMoin下载包里面包含了简单的可执行版本，只需3个步骤就可以运行了。</p>
<ol type="1">
	<li>下载MoinMoin <a href="http://moinmo.in/MoinMoinDownload">http://moinmo.in/MoinMoinDownload</a></li>
	<li>解压缩到合适的目录（安装目录）</li>
	<li>运行目录下面的 <tt>wikiserver.py</tt>
		<ol type="a">
			<li>Linux/Unix：在命令行里面运行 <tt>wikiserver.py</tt></li>
			<li>Mac：在 <tt>wikiserver.py</tt> 上面点击右键，选择 <tt>open with&#8230;</tt> - <tt>All Applications</tt> - <tt>Always Open With</tt> - <tt>Terminal.app</tt></li>
			<li>Windows：下载 <a href="http://www.python.org/download/">Python</a> （2.5-2.6）， 安装之后双击 <tt>wikiserver.py</tt> 运行。</li>
		</ol>
	</li>
</ol>
<p>安装好之后，打开浏览器，在地址栏输入 <a href="http://localhost:8080/">http://localhost:8080/</a> 即可访问。</p>
<p>PS：如果你将MoinMoin安装的优盘，甚至可以做成移动知识库哦~</p>
<p>更多可以参考 <a href="http://moinmo.in/DesktopEdition">官方DesktopEdition帮助文档（英文）</a></p>
<h3><a name="_nginx_uwsgi方式"></a>2.2. nginx+uWsgi方式（程序员适用）</h3>
<p><tt>wikiserver.py</tt> 虽然可以运行，但是作为开发者，我当然要使用效率更高的方式。 运行Python Web应用需要 <tt>Appach / ngnix + CGI / FastCGI / uWSGI</tt> 环境。 我这里使用nginx + uWSGI进行环境配置。</p>
<p>Google了N多资料之后，这篇 <a href="http://typedef.me/2011/08/30/archlinux-nginx-uwsgi-moinmoin-setup">ArchLinux 下使用 Nginx + uWSGI 部署 MoinMoin</a> 最是详细，另外还可以参考 <a href="http://garfileo.is-programmer.com/2011/4/24/run-moinmoin-on-uwsgi-and-nginx.26347.html">运行在 nginx 与 uwsgi 之上的 moinmoin</a>。</p>
<p>我将主要步骤和我的一些修改列出来。</p>
<h4><a name="_安装需要软件"></a>2.2.1. 安装需要软件</h4>
<p>我当前系统是Arch，运行一下命令安装，其他系统也类似</p>
<pre>pacman -S nginx moinmoin
yaourt uwsgi</pre>
<h4><a name="_配置moinmoin"></a>2.2.2. 配置MoinMoin</h4>
<p>默认情况下，moinmoin 被安装在了 <tt>/usr/lib/python2.7/site-packages/MoinMoin</tt> 和 <tt>/usr/moin/share</tt> 这两个目录下。</p>
<pre class="brush: bash;fontsize: 100; first-line: 1; ">cd /usr/share/moin/
ln -s /usr/share/moin/server/moin.wsgi .
ln -s /usr/share/moin/config/wikiconfig.py .</pre>
<h4><a name="_配置nginx"></a>2.2.3. 配置nginx</h4>
<p>在上文的基础上，我做了一些小修改，我的nginx站点配置如下，我没有使用端口9090 作为uwsgi的监听端口，而是使用了UNIX Sock，这样相对安全一些。</p>
<p>ps：貌似这个版本的uwsgi 0.9.9.2有点小问题，无法在 <tt>/var/run</tt> 里面创建sock， 我只能将 <tt>uwsgi.sock</tt> 放在 <tt>/tmp</tt> 里面</p>
<pre class="brush: plain;fontsize: 100; first-line: 1; ">server {
        listen       80;
        server_name  wiki.localhost;
        location /{
                include uwsgi_params;
                #uwsgi_pass 127.0.0.1:9090;
                uwsgi_pass unix:/tmp/uwsgi.sock;
                uwsgi_param UWSGI_PYHOME /usr/lib/python2.7/site-packages/MoinMoin;
                uwsgi_param UWSGI_CHDIR /usr/share/moin;
                uwsgi_param UWSGI_SCRIPT moin_wsgi;
        }
}</pre></p>

<p># vim: set ft=conf:
<h4><a name="_配置启动文件"></a>2.2.4. 配置启动文件</h4>
<p>因为使用 UNIX Sock 连接，所以 <tt>/etc/rc.d/uwsgi</tt> 启动文件也略做修改（ Ubunt 的启动配置文件在 <tt>/etc/init.d/</tt> 下面）， 加入了 <tt>SOCK</tt> ，同时我为 uwsgi 指定运行用户 <tt>http</tt> ，避免root启动带来的安全隐患。</p>
<pre class="brush: bash;fontsize: 100; first-line: 1; ">#!/bin/bash</pre></p>

<p>#PORT=9090<br />
SOCK=/tmp/uwsgi.sock<br />
PROCESSES=4<br />
USER=http<br />
LOG=/var/log/uwsgi.log</p>

<p>PID=`pidof -o %PPID /usr/bin/uwsgi`</p>

<p>. /etc/rc.conf<br />
. /etc/rc.d/functions</p>

<p>case &quot;$1&quot; in<br />
  start)<br />
    stat_busy &quot;Starting uwsgi&quot;<br />
    if [ -n &quot;$PID&quot; ]; then<br />
      stat_busy &quot;uwsgi is already running&quot;<br />
      stat_die<br />
    else<br />
      #uwsgi &#8211;uid $USER -s &quot;:$PORT&quot; -M -p $PROCESSES -d $LOG &amp;&gt; /dev/null # use socket port<br />
      uwsgi &#8211;uid $USER &#8211;socket $SOCK -M -p $PROCESSES -d $LOG &amp;&gt; /dev/null # use unix sock<br />
      add_daemon uwsgi<br />
      stat_done<br />
    fi<br />
    ;;<br />
  stop)<br />
    stat_busy &quot;Stopping uwsgi&quot;<br />
    killall -QUIT uwsgi &amp;&gt; /dev/null<br />
    rm_daemon uwsgi<br />
    stat_done<br />
    ;;<br />
  restart)<br />
    $0 stop<br />
    sleep 1<br />
    $0 start<br />
    ;;<br />
  *)<br />
    echo &quot;usage: $0 {start|stop|restart}&quot;<br />
esac<br />
exit 0
<h2><a name="_image2attach"></a>3. Image2Attach</h2>
<p>去年我选择Wiz而不选择Wiki类产品时候，是考虑到一个图片保存本地化的问题。 即保存一篇网页时候，要将里面的图片保存到本地，而不是使用链接方式保存， 因为由于各种不可预测的原因，原始图片数据很有可能丢失或者无法连接。</p>
<p>Wiz使用的方案是使用mht格式将图片保存在问题，而大部分 Wiki，包括 MoinMoin 都以 文本的形式保存数据，那就无法保存远程图片了。</p>
<p>经我研究，MoinMoin 中有附件的方法可以保存文件，并且当这种附件存放的是图片文件时， 也可以直接使用 <tt></tt> 这样的 Wiki 语法来查看图片。</p>
<p>我尝试在 MoinMoin 插件库里面找将远程图片本地化的插件未果，于是就花了一个星期左右 时间写了一个实现这样功能的插件 Image2Attach。</p>
<p>更多使用可以参考这篇文章 <a href="http://log4d.com/2011/12/moinmoin-plugin-image2attach">MoinMoin plugin: image2attach v0.0.2 released</a></p>
<p>所以说，当程序员就是好，功能没有就自己实现呗。</p>
<h2>4. MoinMoin的简单上手</h2>
<p><a href="http://zhanggang.net/">@张刚</a> 同学发邮件给我和我交流了两个问题，我顺便整理到这里。（2011-12-28更新）</p>
<h3>安装语言包</h3>
<ul>
	<li>首先请确保当前登录账户是超级用户，超级用户设置在 <tt>/usr/share/moin/wikiconfig.py</tt> （可能路径有所差异）里面的 <tt>superuser = [u&quot;yourid&quot;]</tt> ，加入你需要设定的用户id</li>
	<li>中文界面会根据浏览器语言设定获取，而相应的中文帮助文件默认没有安装，我建议安装。安装步骤如下：<br />
		<ul>
			<li>访问http://localhost/LanguageSetup，里面有安装文档链接http://localhost/LanguageSetup?action=language_setup</li>
			<li>在http://wiki.localhost/LanguageSetup?action=language_setup中，选择 <tt>Simplified_Chinese</tt> 点击最下面 <tt>all_pages</tt></li>
			<li>同时我也建议安装英文版本的 <tt>all_pages</tt> ，因为中文有一些翻译不全。</li>
		</ul>
	</li>
</ul>
<p>更多的中文信息你可以访问<a href="http://master.moinmo.in/%E9%A6%96%E9%A1%B5">MoinMoin主版本中文网站</a>。</p>
<h3><a name="_如何加入内容"></a>如何加入内容</h3>
<p>下面是我自己总结的步骤，目前工作的还不错。</p>
<ul>
	<li>进入新页面http://localhost/newpage，如果不存在就会创建新页面</li>
	<li>默认是文本模式编辑器，切换到图形编辑模式（默认编辑器可以在个人设置里面修改）</li>
	<li>从某个网页粘帖内容到图形编辑模式（这个图形编辑器是CKEditor的精简版）。</li>
	<li>查看图形编辑器原始码，再返回&ldquo;所见即所得&rdquo;状态（这个步骤可以去除一些空格）</li>
	<li>返回文本模式编辑器，MoinMoin会自动转换html&rarr;wiki（目前我遇到3个bug，中文开头空格/BR换行/fieldset，前两个我已经修 复，diff文件在<a href="http://upload.log4d.com/2011/12/moinmoin.diff">http://upload.log4d.com/2011/12/moinmoin.diff</a>）</li>
	<li>人工审核一下wiki，也顺便仔细看看文章内容</li>
	<li>加入Category，预览，保存</li>
</ul>
<h2>5. MoinMoin的一些修改</h2>
<p>在使用MoinMoin这段时间，我发现了一些小问题，就对源码做了一些小修改。 当然如果你觉得麻烦，不做这些修改也一样可以使用的很好。</p>
<p>我修改了 <tt>/usr/lib/python2.7/site-packages/MoinMoin/converter/text_html_text_moin_wiki.py</tt> 这个文件。点击 <a href="http://upload.log4d.com/2011/12/moinmoin.diff">diff文件</a>下载。</p>
<h2>6. wiz转MoinMoin经验</h2>
<p>Wiz中数据存储格式其实是mht，微软的鸟东西，数据转换颇为不方便。</p>
<p>第一种方法是借助Wiz Web服务，Wiz小组推出的 <a href="http://service.wiz.cn/web">Web服务</a> 可以很方便的查看所有同步 过的内容，里面就是标准的html代码了，直接可以复制粘帖。Wiz的Web端图片也不用 Cookie认证，取到图片地址就可以抓取了。</p>
<p>另一种办法就是使用Wiz的导出功能，导出成mht格式， 然后使用MoinMoin站点提供的插件 <a href="http://moinmo.in/MicrosoftWordConverter">Word2Moin</a> 脚本进行转换。</p>
<p>我使用的方法是第一种。</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[MoinMoin plugin: image2attach]]></title>
    <link href="http://log4d.com/2011/12/moinmoin-plugin-image2attach/"/>
    <updated>2011-12-18T00:00:00+08:00</updated>
    <id>http://log4d.com/2011/12/moinmoin-plugin-image2attach</id>
    <content type="html"><![CDATA[<p><p><img alt="MoinMoin" height="64" src="http://log4d.com/wp-content/uploads/2011/12/moinmoin.png" width="64" /></p>
<h2>What&rsquo;s this</h2>
<p>Image2Attach is a extension for <a href="http://moinmo.in/">MoinMoin</a>. It can create a page action to save images from web to page&rsquo;s attachments.</p>
<h2><a name="_requirement"></a>Requirement</h2>
<ul>
	<li>MoinMoin 1.9 (I only test in this version.)</li>
</ul>
<h2><a name="_install"></a>Install</h2>
<ul>
	<li>copy action/* to data/plugin/action/</li>
	<li><strike>edit MoinMoin/theme/<em>init</em>.py (update 2012-02-10 ,not need anymore)<br />
		</strike></li>
	<li>restart python server<!--more--></li>
</ul>
<h2><a name="_usage"></a>Usage</h2>
<p>Go into a page, click <tt>More Action</tt> - <tt>Image2Attach</tt>. It will take a while to fetch the images, after that it will save the image to attachments and replace the image&rsquo;s link with attachment&rsquo;s link. Finnally it will commit a change with message &#39;internet image save to attachment&rsquo; to wiki.</p>
<p>Enjoy it, any bugs can report to <a href="https://github.com/alswl/image2attach/issues"> Issue Report</a>.</p>
<p>Source code powered by <a href="https://github.com/alswl/image2attach">https://github.com/alswl/image2attach</a>.</p>
<h2>update 2011-12-25</h2>
<p>+ support link([[http://xxx.com/xxx.jpg|)<br />
	+ fix url has &#39;attachment&#39; string bug.<br />
	+ support image attachment rewrite.</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[更换VPS]]></title>
    <link href="http://log4d.com/2011/12/transfer-vps/"/>
    <updated>2011-12-14T00:00:00+08:00</updated>
    <id>http://log4d.com/2011/12/transfer-vps</id>
    <content type="html"><![CDATA[<p><p>Log4D挂了整整一天，原因是因为VPS扩容导致系统无法启动。</p>
<p>我使用的VPS是<a href="http://www.photonvps.com/billing/aff.php?aff=2188">PhotonVPS</a>的WARP.25套餐。买时候套餐里面硬盘空间是2个G，前几天朋友告诉我新套餐变成了10G。我就发了ticket给客服，他们很快答应帮我升级VPS。我就将数据备份出来，静候升级。</p>
<p>等了半天没反应，又咨询过后才知道新加入的硬盘空间需要重装系统才能启用。好吧，正好我想将CentOS 6换成Arch（Arch用的太顺手了）。</p>
<p>吭次吭次一阵捣鼓（其实重装系统就按一个按钮而已 ^_^），Arch装好了，然后发现系统无法启动了，悲剧鸟。</p>
<p>继续咨询客服，恩，这里插播一下，PhotonVPS的客服回复都是英文，但是可以发送中文过去，貌似有翻译助阵（不过英文文档看多了，简单的也能来两句，hiahia）。客服很快确认，Arch在目前VPS无法正常使用，坑爹阿。</p>
<p>我继续捣鼓，尝试Ubunt/Cent OS，发现都无法启动vps（症状是启动一下下之后立马又变成离线状态）。</p>
<p>继续找客服，最后客服给我重新分配了vps和ip，问题解决。</p>
<p>然我我又开始吭次吭次的装软件，最近系统装多了，手慢慢就熟了。</p>
<p>先升级一下系统<code>apt-get update upgrade</code>，然后创建用户，养成不使用root的好习惯。顺带装一些顺手工具<kbd>vim/git/screen</kbd>。</p>
<p>Ubuntu 11.04下面官方源里面带<kbd>nginx/php5/php-fpm/php-mysql/mysql-server</kbd>，所以不用自己编译可以节省很多时间。</p>
<p>最后装上<kbd>pptpd</kbd>，不解释。</p>
<p>最近的装机事件频发，同志们阿，做好备份，备份才是王道阿。</p>
</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Arch Linux装机软件]]></title>
    <link href="http://log4d.com/2011/12/linux-application/"/>
    <updated>2011-12-11T00:00:00+08:00</updated>
    <id>http://log4d.com/2011/12/linux-application</id>
    <content type="html"><![CDATA[<p><p>重要通知：Log4D的域名由 <a href="http://dddspace.com/">http://dddspace.com</a> 迁移到 <a href="../">http://log4d.com</a> 。</p>
<p>订阅地址现在改为 <a href="../feed">http://log4d.com/feed</a> 和 <a href="http://feeds.feedburner.com/dddspace">http://feeds.feedburner.com/dddspace</a> 。（FeedBurner的地址未发生变化）<br />
	<strike>http://feed.dddspace.com</strike> 弃用</p>
<p>请订阅我博客的朋友更新一下订阅地址。</p>
<p><a name="preamble"></a></p>
<p>前天将arch32位换成64位的系统，想充分利用4G内存。 在mountpoint时候，我mount了 <tt>/root</tt> 和<tt>/home</tt> 盘，然后arch问需要 <tt>(re)create</tt> 分区么。 选项有 <tt>Yes</tt> 和 <tt>No</tt> ，看上去不选 <tt>No</tt> 就进行不下去，我就点了一下。</p>
<p>结果就悲剧了有没有！！！！！！！！！</p>
<p><tt>home</tt> 盘有150G左右有木有！！！！！！！！</p>
<p>日本岛国文化都有70G有木有！！！！！！！！六七年的心血有木有！！！！！</p>
<p>上次备份是2个月前有木有，就算有Dropbox/github/cvs等等，还会丢失变更有木有！！</p>
<p>两个月的数据变化阿，各种文档，照片和音乐阿！！！！！！</p>
<p>你妹的arch格式化之前通知能不能明显一点，弄个 <tt>format</tt> 字眼吓不死我的！！！！</p>
<p>上次备份是放在Dell笔记本里面的，主板坏了打不开有木有！！！！！！！</p>
<p>最后我用移动硬盘装载老电脑的硬盘，勉强把数据恢复过来。</p>
<p>又是一次苦逼的装机路，我一一记录下来。</p>
<p>下面是官方指导文档配置完成之后的软件，在Arch官方库和ARU里面有。<!--more--></p>
<h2><a name="_常用工具"></a>常用工具</h2>
<ul>
	<li>tilda 一个小巧的Terminal Emulator</li>
	<li>fcitx 好用的输入法</li>
</ul>
<h2><a name="_应用软件"></a>应用软件</h2>
<ul>
	<li>asciidoc</li>
	<li>gnucash #财务软件</li>
	<li>libreoffice</li>
	<li>foxitreader #yaourt</li>
	<li>bc #计算器</li>
	<li>text-live-core #LaTex</li>
</ul>
<h2><a name="_网络应用"></a>网络应用</h2>
<ul>
	<li>firefox</li>
	<li>firefox-i18n-zh-cn</li>
	<li>chromium</li>
	<li>dropbox #yaourt</li>
	<li>wakoopa #跟踪系统软件的工具 yaourt</li>
	<li>wireshark-gtk #抓包用的wireshark</li>
	<li>thunderbird</li>
	<li>telepathy #empathy依赖</li>
	<li>nmap #网络工具</li>
</ul>
<h2><a name="_媒体软件"></a>媒体软件</h2>
<ul>
	<li>kid3 #mp3 idv2/idv3编辑器</li>
	<li>gimp</li>
	<li>smplayer #播放器</li>
	<li>rhythmbox #音乐播放器</li>
	<li>audacity #音频编辑器</li>
	<li>k3b #cd刻录</li>
</ul>
<h2><a name="_开发应用"></a>开发应用</h2>
<ul>
	<li>gvim</li>
	<li>git/svn/mercurial/cvs</li>
	<li>ctags</li>
	<li>jdk #yaourt sun官方jdk</li>
	<li>mysql</li>
	<li>mysql-workbench #mysql wrokbench</li>
	<li>nginx</li>
	<li>php</li>
	<li>php-fpm</li>
	<li>python-virtualenv #python版本管理</li>
	<li>python-virtualenvwrapper #pytohn版本管理增强工具</li>
	<li>memcached</li>
</ul>
<h2><a name="_系统工具"></a>系统工具</h2>
<ul>
	<li>net-tools #包含ifconfig/route，这个包现在不在BASE中，默认不安装</li>
	<li>inetutils #包含ftp/telnet，同上</li>
	<li>networkmanager-openconnect #networkmanager相关的插件</li>
	<li>networkmanager-openvpn</li>
	<li>networkmanager-pptp</li>
	<li>networkmanager-dispatcher-sshd</li>
	<li>virtualbox</li>
	<li>virtualbox-addtitions #virtualbox 增强包</li>
	<li>qt</li>
	<li>unrar zip unzip</li>
	<li>flashplugin</li>
	<li>bash-completion #bash自动完成</li>
	<li>nautilus-open-terminal</li>
	<li>avant-window-navigator #dock</li>
	<li>hardinfo #设备信息</li>
	<li>gpaste #多剪贴板 yaourt</li>
	<li>gstreamer0.10-ffmpeg #预览</li>
	<li>gparted #分区工具</li>
	<li>conky #系统运行状态</li>
	<li>ntp #网络时间校准工具</li>
	<li>dnsmasq #本地dns缓存</li>
</ul>
<h2><a name="_gnome相关"></a>gnome相关</h2>
<ul>
	<li>gnome-tweak-tool-3.2.2-2</li>
</ul>
<h2><a name="_gnome_shell扩展"></a>gnome shell扩展</h2>
<p>在 <a href="https://extensions.gnome.org/">https://extensions.gnome.org/</a> 可以下载Gnome3扩展。</p>
<ul>
	<li>Alternative Status Menu</li>
	<li>gTile #桌面多窗口分割</li>
	<li>Places Status Indicator</li>
	<li>Workspace Navigator</li>
</ul>
</p>
]]></content>
  </entry>
  
</feed>

