<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2chinesetwfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>Rest Valley</title>
	
	<link>http://lihdd.net</link>
	<description>The scratchpad of quark</description>
	<lastBuildDate>Sat, 09 Oct 2010 13:56:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/lihdd" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="lihdd" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2Flihdd" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><item>
		<title>去掉 Rainlendar Pro for Linux 的“未注册”字样</title>
		<link>http://lihdd.net/2010/10/remove-unregistered-from-rainlendar-pro/</link>
		<comments>http://lihdd.net/2010/10/remove-unregistered-from-rainlendar-pro/#comments</comments>
		<pubDate>Sat, 09 Oct 2010 13:56:19 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Library]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Rainlendar]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=457</guid>
		<description><![CDATA[很久没有更新 Blog 了。但这并不代表生活索然无味，最近的一段时间， MSRA 总算办夏令营了！于是有幸到在北京玩了六天，见到了许多新老朋友，有许多事情可以说。但如果篇幅有限，只能用一个字来总结这次夏令营，那只能是“热” 实现了 Linux 下的一个通用的 Sandbox，新版本 ZOJ 的后端应该就是它了。同时，发现了现有 ZOJ 几个非常严重的 Bug，真不知道在开源的情况下 ZOJ 是怎么活到现在的，现在想想还是冷汗直流啊 与学校免试研究生相关事情总算告于段落了，结果是和朋友们一起还要在学校呆至少两年多。可以向后来的学弟学妹们传达的信息是，如果不想被直博，那么就趁早准备出国吧&#8230; 做了一些简单的对各种 Web Sever 的性能测试，发现 Thin 表现出色，之前对用 ROR 性能的担忧就减少许多了。新版本的 ZOJ 的前端实现应该就是用它了 跟踪了东方永夜抄并实现了有一些功能的外挂，虽然即便这样，尝试了几次也只能让最高分的最高位达到 4 ，即将到 5，相比之下最高的未作弊记录是 6 &#8230; 用 LaTeX 和一段 Ruby 脚本自动实现集训队的代码模版的排版，相比之前手工用 Word 来排版，就不会出现少一个右括号而导致的悲剧情况了 这些事情有的是属于另外一个大一点的事情的一部分，完成度还没有到一定程度；有的是通过 Google around 再自己调一调就能完成的事情；有的是不适合公开的事情，所以就没有写 那么回到正题，Rainlendar 是一个很好的桌面日历软件，官方非常厚道，未注册的话只会在网络日历事件的工具提示中显示“[UNREGISTERED]”，没有使用时间限制和其他功能限制。而且，只要为 Rainlendar 的翻译做出一点贡献就能免费获得一份授权。 可惜目前中文版的翻译进度是 100%，而授权费用要 100 人名币多，翻一倍再凭借学生证就能买到 Windows 7 正版了，太贵了 那么来自己和谐掉这个“[UNREGISTERED]”吧。 显然，下面的途径都能达到目的： [...]]]></description>
			<content:encoded><![CDATA[<p>很久没有更新 Blog 了。但这并不代表生活索然无味，最近的一段时间，</p>
<ul>
<li>MSRA 总算办夏令营了！于是有幸到在北京玩了六天，见到了许多新老朋友，有许多事情可以说。但如果篇幅有限，只能用一个字来总结这次夏令营，那只能是“热”  <img src='http://lihdd.net/wp-includes/images/smilies/tongue.png' alt=':p' class='wp-smiley' />  </li>
<li>实现了 Linux 下的一个通用的 Sandbox，新版本 <a href="acm.zju.edu.cn">ZOJ</a> 的后端应该就是它了。同时，发现了现有 ZOJ 几个非常严重的 Bug，真不知道在开源的情况下 ZOJ 是怎么活到现在的，现在想想还是冷汗直流啊   <img src='http://lihdd.net/wp-includes/images/smilies/sigh.png' alt=':sigh:' class='wp-smiley' />  </li>
<li>与学校免试研究生相关事情总算告于段落了，结果是和朋友们一起还要在学校呆至少两年多。可以向后来的学弟学妹们传达的信息是，如果不想被直博，那么就趁早准备出国吧&#8230;  <img src='http://lihdd.net/wp-includes/images/smilies/what.png' alt='o.o' class='wp-smiley' />  </li>
<li>做了一些简单的对各种 Web Sever 的性能测试，发现 <a href="http://code.macournoyer.com/thin/">Thin</a> 表现出色，之前对用 <a href="http://rubyonrails.org/">ROR</a> 性能的担忧就减少许多了。新版本的 ZOJ 的前端实现应该就是用它了  <img src='http://lihdd.net/wp-includes/images/smilies/happy.png' alt='(:' class='wp-smiley' /> </li>
<li>跟踪了<a href="http://touhou-wiki.com/index.php?title=%E6%9D%B1%E6%96%B9%E6%B0%B8%E5%A4%9C%E6%8A%84">东方永夜抄</a>并实现了有一些功能的外挂，虽然即便这样，尝试了几次也只能让最高分的最高位达到 4 ，即将到 5，相比之下最高的未作弊记录是 6 &#8230;   <img src='http://lihdd.net/wp-includes/images/smilies/gaah.png' alt='O:' class='wp-smiley' />   </li>
<li>用 LaTeX 和一段 Ruby 脚本自动实现集训队的代码模版的排版，相比之前手工用 Word 来排版，就不会出现少一个右括号而导致的悲剧情况了 <img src='http://lihdd.net/wp-includes/images/smilies/meeh.png' alt='._.' class='wp-smiley' />  </li>
</ul>
<p>这些事情有的是属于另外一个大一点的事情的一部分，完成度还没有到一定程度；有的是通过 Google around 再自己调一调就能完成的事情；有的是不适合公开的事情，所以就没有写  <img src='http://lihdd.net/wp-includes/images/smilies/hmm.png' alt='.~.' class='wp-smiley' /> </p>
<p>那么回到正题，Rainlendar 是一个很好的桌面日历软件，官方非常厚道，未注册的话只会在网络日历事件的工具提示中显示“[UNREGISTERED]”，没有使用时间限制和其他功能限制。而且，只要为 Rainlendar 的翻译做出一点贡献就能免费获得一份授权。<span id="more-457"></span></p>
<p><img src="http://lihdd.net/wp-content/uploads/2010/10/rainlendar_pro_unregistered_tooltip_1.png" alt="" title="rainlendar_pro_unregistered_tooltip_1" width="308" height="67" class="aligncenter size-full wp-image-460" /></p>
<p>可惜目前中文版的翻译进度是 100%，而授权费用要 100 人名币多，翻一倍再凭借学生证就能买到 Windows 7 正版了，太贵了  <img src='http://lihdd.net/wp-includes/images/smilies/sigh.png' alt=':sigh:' class='wp-smiley' />  那么来自己和谐掉这个“[UNREGISTERED]”吧。</p>
<p>显然，下面的途径都能达到目的：</p>
<ul>
<li>和谐掉授权检测部分的代码，让未授权始终通过；进一步地查明授权文件验证方式，算出授权文件</li>
<li>找出并和谐加入“[UNREGISTERED]”字样部分的代码</li>
<li>找到“[UNREGISTERED]”所在的数据段（如果存在），将这个字符串修改成空串</li>
<li>换掉和谐掉显示文字的函数，发现待显示字串中有“[UNREGISTERED]”字样就把他删除了再显示</li>
</ul>
<p>前两种途径难度都很大。那么祈祷一下 “[UNREGISTERED]” 是存在数据段或者是其他文件中的，不过显然作者不会这么弱的…… 于是就换掉显示文字的函数，用 file 命令发现 rainlendar 是动态链接的，那么这个成功的希望比较大。</p>
<p>Rainlendar 链接到了 libpango，那么几乎可以断定它是使用 <a href="http://www.pango.org/">Pango</a> 绘制文字的，容易知道 Pango 绘制文字的函数是 <code>pango_layout_set_text_orig</code>，它的签名是</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> pango_layout_set_text <span style="color: #009900;">&#40;</span>PangoLayout <span style="color: #339933;">*</span>layout<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>text<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> length<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>到这里就很接近成功啦  <img src='http://lihdd.net/wp-includes/images/smilies/happy.png' alt='(:' class='wp-smiley' />  由于 Linux 支持 <a href="http://www.kernel.org/doc/man-pages/online/pages/man8/ld-linux.so.8.html">LD_PRELOAD</a>，那么换掉一个库函数很简单：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;string.h&gt;</span>
<span style="color: #339933;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339933;">#include &lt;dlfcn.h&gt;</span>
&nbsp;
<span style="color: #339933;">#define UNREGISTERED &quot;[UNREGISTERED] &quot;</span>
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>libpango<span style="color: #339933;">;</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>pango_layout_set_text_orig<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*,</span> <span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
__attribute__<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>__constructor__<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #993333;">void</span> pango_hook_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	libpango <span style="color: #339933;">=</span> dlopen<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;libpango-1.0.so&quot;</span><span style="color: #339933;">,</span> RTLD_LOCAL  <span style="color: #339933;">|</span> RTLD_LAZY<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	pango_layout_set_text_orig <span style="color: #339933;">=</span> dlsym<span style="color: #009900;">&#40;</span>libpango<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;pango_layout_set_text&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> pango_layout_set_text<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span>layout<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>text<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> length<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">char</span> <span style="color: #339933;">*</span>p <span style="color: #339933;">=</span> text <span style="color: #339933;">?</span> strstr<span style="color: #009900;">&#40;</span>text<span style="color: #339933;">,</span> UNREGISTERED<span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>__builtin_expect<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">long</span><span style="color: #009900;">&#41;</span>p<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #993333;">int</span> len <span style="color: #339933;">=</span> length <span style="color: #339933;">&gt;=</span> <span style="color: #0000dd;">0</span> <span style="color: #339933;">?</span> length <span style="color: #339933;">:</span> strlen<span style="color: #009900;">&#40;</span>text<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		memmove<span style="color: #009900;">&#40;</span>p<span style="color: #339933;">,</span> p <span style="color: #339933;">+</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>UNREGISTERED<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
			<span style="color: #009900;">&#40;</span>len <span style="color: #339933;">-=</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>UNREGISTERED<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #009900;">&#40;</span>p <span style="color: #339933;">-</span> text<span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>length <span style="color: #339933;">&gt;=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> length <span style="color: #339933;">=</span> len<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	pango_layout_set_text_orig<span style="color: #009900;">&#40;</span>layout<span style="color: #339933;">,</span> text<span style="color: #339933;">,</span> length<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>使用 <code>gcc $^ -fPIC -shared -o libpango_hook.so -ldl</code> 将上面的代码编译成动态链接库文件 libpango_hook.so，接着修改 /usr/bin/rainlendar，在运行 Rainlendar 之前，正确设置好 LD_PRELOAD，大概是这个样子：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/dash</span>
<span style="color: #007800;">RAINLENDAR_PATH</span>=<span style="color: #ff0000;">'/opt/rainlendar2'</span>
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">LD_PRELOAD</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$RAINLENDAR_PATH</span>/libpango_hook.so&quot;</span>
<span style="color: #7a0874; font-weight: bold;">exec</span> <span style="color: #007800;">$RAINLENDAR_PATH</span><span style="color: #000000; font-weight: bold;">/</span>rainlendar2</pre></div></div>

<p>接着祈祷一下 Rainlendar 不是通过 dlopen 再 dlsym 的方式定位 pango_layout_set_text 这个函数的，那么事实证明它确实不是这样的 <img src='http://lihdd.net/wp-includes/images/smilies/very_happy.png' alt='^_^' class='wp-smiley' /> </p>
<p><img class="aligncenter size-full wp-image-461" title="rainlendar_pro_unregistered_tooltip_2" src="http://lihdd.net/wp-content/uploads/2010/10/rainlendar_pro_unregistered_tooltip_2.png" alt="" width="308" height="67" /></p>
<p>虽然中文字体不好看，但是“[UNREGISTERED]”不见了。</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=7UDSJZXHZrc:IHzEBnPFWzc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=7UDSJZXHZrc:IHzEBnPFWzc:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/7UDSJZXHZrc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/10/remove-unregistered-from-rainlendar-pro/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>坏道惊魂</title>
		<link>http://lihdd.net/2010/05/seagate-bad-blocks/</link>
		<comments>http://lihdd.net/2010/05/seagate-bad-blocks/#comments</comments>
		<pubDate>Mon, 10 May 2010 13:35:52 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Config]]></category>
		<category><![CDATA[badblocks]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[seagate]]></category>
		<category><![CDATA[smartctl]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=417</guid>
		<description><![CDATA[天气渐渐热了起来，听着本本风扇狂转的声音，右手感觉到硬盘滚烫的温度，我觉得现有数据很是需要备份一下。 我以前一直觉得坏道什么的太难遇到了，直到去年十二月的一天，类似这样的消息在屏幕出现： kernel: sd 4:0:0:0: [sda] Unhandled sense code kernel: sd 4:0:0:0: [sda] Result: hostbyte=0x00 driverbyte=0x08 kernel: sd 4:0:0:0: [sda] Sense Key : 0x3 [current] kernel: sd 4:0:0:0: [sda] ASC=0x14 ASCQ=0x0 kernel: sd 4:0:0:0: [sda] CDB: cdb[0]=0x28: 28 00 25 42 ea af 00 00 01 00 kernel: end_request: I/O error, dev sda, sector 625142447 [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-418" title="drive-harddisk" src="http://lihdd.net/wp-content/uploads/2010/05/drive-harddisk.png" alt="" width="128" height="128" align="right" />天气渐渐热了起来，听着本本风扇狂转的声音，右手感觉到硬盘滚烫的温度，我觉得现有数据很是需要备份一下。</p>
<p>我以前一直觉得坏道什么的太难遇到了，直到去年十二月的一天，类似这样的消息在屏幕出现：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">kernel: sd 4:0:0:0: [sda] Unhandled sense code
kernel: sd 4:0:0:0: [sda] Result: hostbyte=0x00 driverbyte=0x08
kernel: sd 4:0:0:0: [sda] Sense Key : 0x3 [current]
kernel: sd 4:0:0:0: [sda] ASC=0x14 ASCQ=0x0
kernel: sd 4:0:0:0: [sda] CDB: cdb[0]=0x28: 28 00 25 42 ea af 00 00 01 00
kernel: end_request: I/O error, dev sda, sector 625142447
kernel: Buffer I/O error on device sda, logical block 78142805</pre></div></div>

<p>这些消息会反复地出现，持续三分钟左右，在此期间做不得其他事情。这些消息出现在对磁盘执行 mount 或 fsck 之前，也就是说系统刚发现这个硬盘还没有开始挂载的时候，就会僵持三分钟。当然，等到 mount 的时候，又是一个三分钟。换句话说，光是进入 Linux 系统就需要六分多钟。神奇的是 Windows 并不会僵持住  <img src='http://lihdd.net/wp-includes/images/smilies/icon_eek.gif' alt='8-O' class='wp-smiley' /> </p>
<p>查阅一些资料之后，排除了是内核 Bug 或者是参数设置不正确，了解到那些稀奇古怪的十六进制数字背后还有一些标准，我终于相信坏道就在眼前。实在忍受不了需要六分钟才能进入 Linux 系统，同时我也担心坏道会扩散，就在第二天去换了一个一样容量的硬盘。</p>
<p>最近，出于备份的需要有把这块硬盘拿出来了，那么怎么处理坏道呢？</p>
<p><span id="more-417"></span>传统的方法可能是用 <code>badblocks</code> 这个程序去检测一下坏道在哪里了。<code>badblocks</code> 有两种检查方式，一种是只读的，一种是读写的。一般想要彻底查出来坏道就要选择读写的方法，而 <code>badblocks</code> 在这时会依次填上 0xaa, 0&#215;55, 0xff, 0&#215;00，并分别读一次来确认是否有坏道。 <code>badblocks</code> 没有特别的优化，倘若填写 0xaa 之后检查的时候就发现需要检查的所有区域都已经坏掉了， <code>badblocks</code> 并不会终止检查，而是会傻傻地执行完剩下的所有检查。对于一块 320G 笔记本硬盘来说，全盘的读写检查大概需要 24 个小时。</p>
<p>在 <code>badblocks</code> 全盘读写检查的第 18 个小时，我不小心一个操作把它终止掉了 <img src='http://lihdd.net/wp-includes/images/smilies/icon_neutral.gif' alt=':-|' class='wp-smiley' />  。这么漫长的操作肯定不愿意再来一次了，于是我用了一次 <code>badblocks</code> 全盘只读检查，结果 <code>badblocks</code> 说没有发现坏道 &#8230;</p>
<p>查阅相关资料后发现，从一开始就用不到 <code>badblocks</code>。现代硬盘具有自我检查机制，在一个“坏道”彻底坏掉之前的很长时间，它先是在读取的时候变得困难，而不是完全无法读取（希捷官方所言）。这时候，支持 <a href="http://en.wikipedia.org/wiki/S.M.A.R.T.">SMART</a> 标准的硬盘（许多年前的有硬盘就都普遍支持了）会防患于未然，把这个 sector 记录成 &#8220;Pending&#8221;，用 <code>smartctl</code> 命令就可以查看到 Current Pending Sector：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;"># smartctl -A /dev/sdb
....
... Current_Pending_Sector ... 1
....</pre></div></div>

<p>这就表明硬盘自己发现了一个不稳定的 sector 了，这时候，如果读写这个 sector 变得正常的话，这个 sector 会被硬盘记录成正常，Current Pending Sector 会减少。如果依然发生了读取困难或者是不能读取的情况，硬盘不会做任何事情。当写入失败的时候，硬盘会自动将这个 sector 映射到它的保留区的一个好的 sector，并把这个 sector 标记成 &#8220;remapped&#8221;，由于一般坏道在真正坏掉之前还是可以读出内容的，硬盘会自动将读出来的内容复制到保留区，remap 完成之后，Current Pending Sector 也会减少，这一切都是在硬件层面上完成的，如果正常的话，普通软件（比如 <code>badblocks</code>）是根本没法发现这个 sector 是坏掉的，即便它去写那个 sector。</p>
<p>那么问题是不是就变得简单了呢，向标记为 Pending 的 sector 写一点东西就可以让硬件搞定这些问题了？看起来是的。在写之前需要知道有问题的 sector 在哪里，这个在 kernel log 里面已经看到了。现代的硬盘自己也会记录错误的 log，通过 <code>smartctl /dev/sdb -l error</code> 命令就能查看，虽然数量有限（我这里只有最后的 5 条），不一定会看到想要看的错误信息。</p>
<p>通过 fdisk 可以看到一个 sector 的大小：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;"># fdisk -lu /dev/sdb
&nbsp;
Disk /dev/sdb: 320.1 GB, 320072933376 bytes
255 heads, 63 sectors/track, 38913 cylinders, total 625142448 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
....</pre></div></div>

<p>按照文章开头处 kernel log 中提到的 625142447，向这个地方写一点东西，让硬盘立即 remap 这个 Pending Sector：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;"># dd if=/dev/zero of=/dev/sdb bs=512 count=1 seek=625142447
dd: writing `/dev/sdb': Input/output error
1+0 records in
0+0 records out
0 bytes (0 B) copied, 7.26951 s, 0.0 kB/s</pre></div></div>

<p>有的朋友可能读到这里就发现我悲剧了，因为如果硬件正常的话，它会进行 remap，然后就能写成功了，但显然事与愿违，硬盘没有进行 remap，这时用 <code>badblocks</code> 也能发现这个坏道：</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;"># badblocks -svw -b 512 /dev/sdb 625142447 625142447
Checking for bad blocks in read-write mode
From block 625142447 to 625142447
Testing with pattern 0xaa: done
625142447
Reading and comparing: done
Testing with pattern 0x55: done
Reading and comparing: done
Testing with pattern 0xff: done
Reading and comparing: done
Testing with pattern 0x00: done
Reading and comparing: done
Pass completed, 1 bad blocks found.</pre></div></div>

<p>用 <code>smartctl</code> 可以验证 Current Pending Sector 还是 1，并没有变成 0。一切都没有改变，所有的硬盘 SMART 自检都会失败，kernel 还是会产生那样的 log，并持续几十秒挡住你，不让用这块硬盘。</p>
<p>这时候我突然想到了这块希捷硬盘可能还在保修期  <img src='http://lihdd.net/wp-includes/images/smilies/icon_eek.gif' alt='8-O' class='wp-smiley' /> </p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">厂商保修信息：
    * 该商品保修期为36个月。
    * 3 年有限责任质保(第一年免费包换，第二，三年保修)</pre></div></div>

<p>看起来只能换不能修了，早知道在刚出问题的时候就去换一个了 <img src='http://lihdd.net/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  想到 Windows 下使用没有问题，说清楚问题所在还是挺麻烦的。并且邮寄费用并不便宜，寄来寄去说不定还会导致彻底坏掉了，还是不要修了 &#8230;.</p>
<p>绝望中突然看到了希望，那就是希捷硬盘可以使用的 <a href="http://www.seagate.com/www/en-us/support/downloads/seatools">SeaTools</a> 。它有两个版本，Windows 版能做的事情比 <code>smartctl</code> 命令还要少，真的没啥用，而且把希捷自家的硬盘放到外面的盒子里就认不出来是希捷的了。不过官方说 DOS 版本能修复坏道，这应该是最后的希望了。</p>
<p>于是赶紧下载，刻录成光盘，由于 SeaTools for DOS 不支持移动硬盘，就把现在用的硬盘换下来，用光盘启动，见到了久违的 FreeDOS 。SeaTools for DOS 的坏道修复功能不依靠 SMART 信息，需要执行一次全盘扫描，扫描用了两个小时，接着果然提供了一个 Repair 选项，果断使用，成功了 <img src='http://lihdd.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  在此之后这快硬盘用起来完全正常，即便查看 SMART 信息也看不出来有一个坏道被映射了。SeaTools for DOS 还提供了设置硬盘容量的功能，实际上这次有问题的 sector 就是整个硬盘有效 sector 的倒数第二个，修改硬盘容量，减少 1 MB，也应该是解决问题的不错办法。</p>
<p>总结起来，这次这个事情之后有一些经验：</p>
<ol>
<li>对于硬盘健康情况的检测，<code>badblocks</code> 这种东西太旧了，而且对现代硬盘也不一定有效。<code>smartctl</code> 可以多快好省地完成许多相关事情。</li>
<li>虽然 SMART 是存在好多年的标准，但硬件不一定完全遵守它。厂商自己提供的工具才是最靠谱的！更广泛一点，软件和标准也是这样。</li>
<li><code>palimpsest</code> 用来查看 SMART 信息和做硬盘自检很不错，如果不喜欢命令行的 <code>smartctl</code> 就可以用它。而 <code>gparted</code> 则侧重于做编辑分区的工作。<div id="attachment_419" class="wp-caption aligncenter" style="width: 310px"><a href="http://lihdd.net/wp-content/uploads/2010/05/palimpsest_smart_info.png"><img class="size-medium wp-image-419 " title="palimpsest_smart_info" src="http://lihdd.net/wp-content/uploads/2010/05/palimpsest_smart_info-300x251.png" alt="" width="300" height="251" /></a><p class="wp-caption-text">用 Palimpsest 查看硬盘的 SMART 信息</p></div></li>
<li>Linux 可以早于 Windows 发现磁盘可疑坏道，可疑坏道出现后的很长一段时间内还是可以读取的，只是硬盘要多用一点力气。</li>
<li>发现硬盘问题时应该立即换下可疑硬盘，备份数据到可靠的硬盘里，再考虑修复。除非很了解正在使用的 FS，掌握 <code>debugfs</code> 等的用法，否则不要直接尝试在线修复坏道。</li>
<li>定期使用如 <code>rsync</code> 的软件备份数据到别的地方，硬盘数据，正如国歌中的中华民族，到了最危险的时候。</li>
<li>有时候见到把硬盘的最后 8 MB 空出来，不分到任何分区去，也许是有一定道理的。</li>
</ol>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=KYDGxWZzQ0s:NeytWKvV_08:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=KYDGxWZzQ0s:NeytWKvV_08:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/KYDGxWZzQ0s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/05/seagate-bad-blocks/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>让 Archlinux 的 pacman 健步如飞</title>
		<link>http://lihdd.net/2010/05/archlinux-pacman-accelerate/</link>
		<comments>http://lihdd.net/2010/05/archlinux-pacman-accelerate/#comments</comments>
		<pubDate>Wed, 05 May 2010 01:38:46 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Config]]></category>
		<category><![CDATA[archlinux]]></category>
		<category><![CDATA[pacman]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=403</guid>
		<description><![CDATA[使用 Archlinux 的朋友大概遇到过这样的烦恼，软件安装得比较多的时候，再用 pacman 做任何事情的时候都可以看到硬盘狂转一段时间，然后才有反应。 pacman 官方给了一个 pacman-optimize，它会把 pacman 数据库文件打包到别的地方，删除，然后再放回去。这样做可能会让这些零碎的文件在硬盘上是连续排列的，但实际效果却不是很好。 虽然用 Archlinux 应该有三年左右了，但我还从来没有看过 pacman 的数据库是什么模样。有一天终于忍不住去看了一下 /var/lib/pacman 下面到底是什么，原来是这么多零碎的小文件啊！ 于是解决方案也就有了：把所谓的 pacman 数据库放到 reiserfs 文件系统里。如果你本来在这个地方用的就是 reiserfs 的话，那么不需要做任何事情， pacman 应该就很快了。如果你和我一样用的是 ext4 这样的文件系统，也不必慌张地把整个分区都换成 reiserfs。 新建一个 160 MB 的 reiserfs 文件 pacman_db.fs： truncate pacman_db.fs --size 160M mkfs.reiserfs -f ./pacman_db.fs 把现有的 pacman 数据库复制到这个 reiserfs 里面： sudo mount pacman_db.fs -t reiserfs /mnt -o [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://lihdd.net/wp-content/uploads/2010/05/pacman.png"><img class="alignright size-full wp-image-404" title="pacman" src="http://lihdd.net/wp-content/uploads/2010/05/pacman.png" alt="pacman" width="128" height="119" /></a>使用 Archlinux 的朋友大概遇到过这样的烦恼，软件安装得比较多的时候，再用 <code>pacman</code> 做任何事情的时候都可以看到硬盘狂转一段时间，然后才有反应。</p>
<p><code>pacman</code> 官方给了一个 <code>pacman-optimize</code>，它会把 <code>pacman</code> 数据库文件打包到别的地方，删除，然后再放回去。这样做可能会让这些零碎的文件在硬盘上是连续排列的，但实际效果却不是很好。</p>
<p>虽然用 Archlinux 应该有三年左右了，但我还从来没有看过 <code>pacman</code> 的数据库是什么模样。有一天终于忍不住去看了一下 <code>/var/lib/pacman</code> 下面到底是什么，原来是这么多零碎的小文件啊！</p>
<p>于是解决方案也就有了：把所谓的 <code>pacman</code> 数据库放到 reiserfs 文件系统里。如果你本来在这个地方用的就是 reiserfs 的话，那么不需要做任何事情， <code>pacman</code> 应该就很快了。如果你和我一样用的是 ext4 这样的文件系统，也不必慌张地把整个分区都换成 reiserfs。<span id="more-403"></span></p>
<p>新建一个 160 MB 的 reiserfs 文件 <code>pacman_db.fs</code>：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">truncate pacman_db.fs <span style="color: #660033;">--size</span> 160M
mkfs.reiserfs <span style="color: #660033;">-f</span> .<span style="color: #000000; font-weight: bold;">/</span>pacman_db.fs</pre></div></div>

<p>把现有的 <code>pacman</code> 数据库复制到这个 reiserfs 里面：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mount</span> pacman_db.fs <span style="color: #660033;">-t</span> reiserfs <span style="color: #000000; font-weight: bold;">/</span>mnt <span style="color: #660033;">-o</span> loop 
<span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #660033;">-a</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>pacman<span style="color: #000000; font-weight: bold;">/*</span> <span style="color: #000000; font-weight: bold;">/</span>mnt
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">umount</span> <span style="color: #000000; font-weight: bold;">/</span>mnt</pre></div></div>

<p>接下来修改 <code>/etc/fstab</code>，加上一行：</p>

<div class="wp_syntax"><div class="code"><pre class="auto" style="font-family:monospace;">/[path_to_pacman_db]/pacman_db.fs /var/lib/pacman reiserfs defaults,loop 0 4</pre></div></div>

<p>左边的 <code>[path_to_pacman_db]</code> 需要根据实际情况填一下。最右边的 4 应该是比 <code>fstab</code> 中其他条目大一些的数字，表示 <code>fsck</code> 检查时最后处理这个地方。</p>
<p>如果想让这个设置立即生效，执行 <code>sudo mount /var/lib/pacman</code> 即可。否则，重启一下就可以了。现在，使用 <code>pacman -Syu</code> 更新一下系统，是不是比以前快许多？ <img src='http://lihdd.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=uEm2LgmsYFE:YNFnGu8PSH0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=uEm2LgmsYFE:YNFnGu8PSH0:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/uEm2LgmsYFE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/05/archlinux-pacman-accelerate/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>大清谷烧烤之旅</title>
		<link>http://lihdd.net/2010/05/daqing-valley-icebreaking/</link>
		<comments>http://lihdd.net/2010/05/daqing-valley-icebreaking/#comments</comments>
		<pubDate>Tue, 04 May 2010 16:33:54 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[MSTC]]></category>
		<category><![CDATA[travel]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=388</guid>
		<description><![CDATA[新学期 MSTC 纳新了许多小朋友，大家决定在五月二日去大清谷烧烤，互相认识一下。 由于五一期间回家还有去上海等原因，有的同学没能来。最后出游的有 20 个人，人数上看还是很不错的 到达大清谷后，大家凑了几张桌子围坐在一起，按照 CG 策划活动，两两互相认识，然后再介绍给大家。 不厚道的老人们坐在了一起，明显降低了游戏难度，傻笑中： 不得不提到这一次纳新造就的新一代 MSTC mm 寝室，四位报名纳新的 mm 都被 accepted 了！虽然这次有一位没有能来，有些遗憾： 很快就到了中午的烧烤时间。这一次的烧烤虽然准备材料有些不够充分，但是就视觉和味觉来说，都是很赞的！ 这是烤玉米，看着有食欲吗？没有食欲吗？ 我之前一直觉得烧烤烧不好也吃不饱，从这一天开始，看法发生改变了 下午的时间，大家并分两路，有的去爬山，有的在屋里玩游戏。我跟着去爬山了，这次爬山是完全不知道路线的。于是，上次去法喜寺那样暴走的情况是不会再出现了 实际上，不少同学的手机都支持 GPS，大概想迷路也不大可能，哈哈。 盲目的深度优先遍历，到了某个亭子，发现已经有组织留下记号了： 文艺青年 Stingrey 正在记录众人休息的场景： 路上遇到的小白花： 天很蓝，而云很白，风不凉： 隧道中，“黎明前的黑暗”： 说起来这是我第一次步行经过隧道呢，穿过隧道，就可以看到未命名的泉水，很清也很凉： 其实又走了两步就发现是回去的道路了，深度优先遍历到此就该退出了。同样的路，回去的时候却觉得好长好长，出发的时候一点都不觉得。 接下来的是流行牌类游戏三国杀： 太累了，有两位小朋友先睡着了 ： 大家玩的应该都很尽兴。虽然没有像上次去法喜寺那样累得半死，但我回到寝室后困得不行，倒下就睡着了。在此同时，MSTC mm 们在玉泉校区附近逛街，真的很有体力啊。 惭愧的是，虽然这次活动目的是破冰，我却只认识了寥寥无几的新人 不过，以后还有很多机会的，期待一下吧]]></description>
			<content:encoded><![CDATA[<p>新学期 MSTC 纳新了许多小朋友，大家决定在五月二日去大清谷烧烤，互相认识一下。</p>
<p>由于五一期间回家还有去上海等原因，有的同学没能来。最后出游的有 20 个人，人数上看还是很不错的  <img src='http://lihdd.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
<span id="more-388"></span></p>
<p>到达大清谷后，大家凑了几张桌子围坐在一起，按照 CG 策划活动，两两互相认识，然后再介绍给大家。</p>
<p>不厚道的老人们坐在了一起，明显降低了游戏难度，傻笑中：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_morning.jpg"><img class="alignnone size-full wp-image-389" title="daqing_valley_morning" src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_morning.jpg" alt="大清早到达大清谷的大伙们" width="574" height="372" /></a></p>
<p>不得不提到这一次纳新造就的新一代 MSTC mm 寝室，四位报名纳新的 mm 都被 accepted 了！虽然这次有一位没有能来，有些遗憾：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_mstcmms.jpg"><img class="alignnone size-full wp-image-390" title="daqing_valley_mstcmms" src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_mstcmms.jpg" alt="MSTC mms" width="574" height="411" /></a></p>
<p>很快就到了中午的烧烤时间。这一次的烧烤虽然准备材料有些不够充分，但是就视觉和味觉来说，都是很赞的！</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_barbeque.jpg"><img class="alignnone size-full wp-image-391" title="daqing_valley_barbeque" src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_barbeque.jpg" alt="烧烤" width="574" height="350" /></a></p>
<p>这是烤玉米，看着有食欲吗？没有食欲吗？</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_rosted_cron.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_rosted_cron.jpg" alt="烤玉米" title="daqing_valley_rosted_cron" width="574" height="433" class="alignnone size-full wp-image-392" /></a></p>
<p>我之前一直觉得烧烤烧不好也吃不饱，从这一天开始，看法发生改变了  <img src='http://lihdd.net/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' />  </p>
<p>下午的时间，大家并分两路，有的去爬山，有的在屋里玩游戏。我跟着去爬山了，这次爬山是完全不知道路线的。于是，上次去法喜寺那样暴走的情况是不会再出现了  <img src='http://lihdd.net/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' />  实际上，不少同学的手机都支持 GPS，大概想迷路也不大可能，哈哈。</p>
<p>盲目的深度优先遍历，到了某个亭子，发现已经有组织留下记号了：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_yongkang.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_yongkang.jpg" alt="“永康登山队”到此一游" title="daqing_valley_yongkang" width="574" height="469" class="alignnone size-full wp-image-393" /></a></p>
<p>文艺青年 <a href="http://hi.baidu.com/Stingrey">Stingrey</a>  正在记录众人休息的场景：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_stingrey.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_stingrey.jpg" alt="文艺青年 Stingrey" title="daqing_valley_stingrey" width="574" height="412" class="alignnone size-full wp-image-394" /></a></p>
<p>路上遇到的小白花：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_white_flowers.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_white_flowers.jpg" alt="路上的小白花" title="daqing_valley_white_flowers" width="574" height="383" class="alignnone size-full wp-image-395" /></a></p>
<p>天很蓝，而云很白，风不凉：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_sky.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_sky.jpg" alt="天很蓝，云很白" title="daqing_valley_sky" width="574" height="364" class="alignnone size-full wp-image-396" /></a></p>
<p>隧道中，“黎明前的黑暗”：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_tunnel_end.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_tunnel_end.jpg" alt="黎明前的黑暗" title="daqing_valley_tunnel_end" width="574" height="415" class="alignnone size-full wp-image-397" /></a></p>
<p>说起来这是我第一次步行经过隧道呢，穿过隧道，就可以看到未命名的泉水，很清也很凉：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_brook.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_brook.jpg" alt="潺潺流水" title="daqing_valley_brook" width="574" height="363" class="alignnone size-full wp-image-398" /></a></p>
<p>其实又走了两步就发现是回去的道路了，深度优先遍历到此就该退出了。同样的路，回去的时候却觉得好长好长，出发的时候一点都不觉得。</p>
<p>接下来的是流行牌类游戏三国杀：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_sanguosha.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_sanguosha.jpg" alt="三国杀中的众人" title="daqing_valley_sanguosha" width="574" height="386" class="alignnone size-full wp-image-399" /></a></p>
<p>太累了，有两位小朋友先睡着了  <img src='http://lihdd.net/wp-includes/images/smilies/icon_eek.gif' alt='8-O' class='wp-smiley' />  ：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_sleeping_boys.jpg"><img src="http://lihdd.net/wp-content/uploads/2010/05/daqing_valley_sleeping_boys.jpg" alt="睡着了的小朋友" title="daqing_valley_sleeping_boys" width="574" height="397" class="alignnone size-full wp-image-400" /></a></p>
<p>大家玩的应该都很尽兴。虽然没有像上次去法喜寺那样累得半死，但我回到寝室后困得不行，倒下就睡着了。在此同时，MSTC mm 们在玉泉校区附近逛街，真的很有体力啊。</p>
<p>惭愧的是，虽然这次活动目的是破冰，我却只认识了寥寥无几的新人 <img src='http://lihdd.net/wp-includes/images/smilies/icon_confused.gif' alt=':-?' class='wp-smiley' />  不过，以后还有很多机会的，期待一下吧  <img src='http://lihdd.net/wp-includes/images/smilies/icon_rolleyes.gif' alt=':roll:' class='wp-smiley' />  </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=tbvlcq3Ll6g:nrdzv9paOhA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=tbvlcq3Ll6g:nrdzv9paOhA:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/tbvlcq3Ll6g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/05/daqing-valley-icebreaking/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>腾讯微博的 twitter 样式</title>
		<link>http://lihdd.net/2010/04/tencent-microblog-twitter-style/</link>
		<comments>http://lihdd.net/2010/04/tencent-microblog-twitter-style/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 15:17:40 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Artwork]]></category>
		<category><![CDATA[microblog]]></category>
		<category><![CDATA[stylish]]></category>
		<category><![CDATA[tencent]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=376</guid>
		<description><![CDATA[最近腾讯微博开始流行起来，到处散发邀请码。我本来不愿意注册的，但是却由于好奇没有坚持住。 虽然我自己没有邀请码，不过在 twitter 上搜索 “invite” 之后就有了，半分钟之内的新邀请码。不得不感慨一下 twitter 实时搜索的强大和有用，今年春节联欢晚会的时候，我就在实时搜索 #chunwan，屏幕上不停地出现来自世界各地的更新，对电视中正在播放的节目做评论，这是一种前所未有的及时的信息流通感觉。现在虽然没有那么强烈的感觉，但是邀请码显然用其他搜索途径都找不到的…… 腾讯微博考虑到了广大的 IE6 用户，没有使用 CSS3 。目前看来也没有自定义背景、设置是否 Protected 的选项，更不要期望 API 了。虽然今后大概不会太关注它，但是将来肯定是有许多身边的朋友会把它当做第一微博的，所以偶尔也会去看一下。我不太喜欢腾讯微博的默认主题，就按照 rabr 的样子改成了下面的结果： 其实是很简单的 Stylish CSS，我把它上传到了userstyles.org 那里， Hope it is useful for you note: 样式是为 Firefox 制作的，其中用到了 -moz-border-radius 来实现圆角。如果使用别的浏览器的话，这个地方要修改一下。 update: 现在已经不需要了。]]></description>
			<content:encoded><![CDATA[<p>最近腾讯微博开始流行起来，到处散发邀请码。我本来不愿意注册的，但是却由于好奇没有坚持住。</p>
<p>虽然我自己没有邀请码，不过在 twitter 上搜索 “invite” 之后就有了，半分钟之内的新邀请码。不得不感慨一下 twitter 实时搜索的强大和有用，今年春节联欢晚会的时候，我就在实时搜索 <code>#chunwan</code>，屏幕上不停地出现来自世界各地的更新，对电视中正在播放的节目做评论，这是一种前所未有的及时的信息流通感觉。现在虽然没有那么强烈的感觉，但是邀请码显然用其他搜索途径都找不到的……</p>
<p>腾讯微博考虑到了广大的 IE6 用户，没有使用 CSS3 。目前看来也没有自定义背景、设置是否 Protected 的选项，更不要期望 API 了。虽然今后大概不会太关注它，但是将来肯定是有许多身边的朋友会把它当做第一微博的，所以偶尔也会去看一下。我不太喜欢腾讯微博的默认主题，就按照 rabr 的样子改成了下面的结果：</p>
<div id="attachment_377" class="wp-caption aligncenter" style="width: 310px"><a href="http://lihdd.net/wp-content/uploads/2010/04/tencent_microblog_twitter_style.png"><img class="size-medium wp-image-377 " title="tencent_microblog_twitter_style" src="http://lihdd.net/wp-content/uploads/2010/04/tencent_microblog_twitter_style-300x159.png" alt="" width="300" height="159" /></a><p class="wp-caption-text">腾讯微博的自定义样式</p></div>
<p>其实是很简单的 Stylish CSS，我把它上传到了<a href="http://userstyles.org/styles/28684">userstyles.org 那里</a>， Hope it is useful for you <img src='http://lihdd.net/wp-includes/images/smilies/happy.png' alt='(:' class='wp-smiley' /> <span id="more-376"></span></p>
<p>note: 样式是为 Firefox 制作的，其中用到了 <code>-moz-border-radius</code> 来实现圆角。如果使用别的浏览器的话，这个地方要修改一下。</p>
<p>update: 现在已经不需要了。</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=fvymnZqk780:Nr8ka2EdLNY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=fvymnZqk780:Nr8ka2EdLNY:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/fvymnZqk780" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/04/tencent-microblog-twitter-style/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>校赛又一年</title>
		<link>http://lihdd.net/2010/04/university-acm-contest-2010/</link>
		<comments>http://lihdd.net/2010/04/university-acm-contest-2010/#comments</comments>
		<pubDate>Sat, 10 Apr 2010 17:53:14 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[icpc]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=368</guid>
		<description><![CDATA[又是一年校赛，和去年相比，今年的队友以及我的想法都很不一样了。 解题报告推荐看hhanger裁判的版本，十分好。我这里是流水账，不要在这里期待什么 早上的闹铃响了，意识到 8:45 是报名截止时间。速度赶去紫金港校区，结果发现来得比较早了，报名也不需要三个人的学生证，队友 asmn 准备吃完午饭再过来 。很快找到了 moondy 一行人，一起去吃早饭，看来没有在玉泉校区解决早饭是明智的啊。 抽签是 007 号，还在用 CRT 显示器的一个机房，不过距离打印机特别近。学校的机器一如既往地存在着 Netbeans 3.x，试验了 Java， Dev-cpp 和 IE 浏览器没有问题之后，又玩了玩 cygwin。大概我们试的东西有些多，我到其他机房去串门的时候，认识的人已经很少了 我觉得比赛的时候喝水比较重要，asmn 可能会没有准备齐全就赶过来，就去超市买了一些饮料和三支笔。回到 218 之后看着 watashi 在笔记本上玩游戏，仰慕之中很快眼花了，睡了一会儿。醒来的时候大家就都到齐了，很快进入了赛场。赛场外围有非常多的粉红色气球，是 A，想必这一题必须很简单了吧。 moondy 带去了 vls 的吉祥物，看起来很可爱的样子，不知道有没有被拍下来。赛后 asmn 好奇起来，去扒吉祥物的衣服，被 moody 制止了 -_- 比赛开始后，我填写了登陆信息，设置好 Dev-cpp，然后 moondy 说 A 题不会做，好在 asmn 看过后很快秒杀了。lam 送来了第一个气球，大家都比较兴奋。接着 moondy 把 I 题秒杀了，我却还在读中间的三道题，我发现 E 题很容易的样子，写了一半发现输入中的 t1 [...]]]></description>
			<content:encoded><![CDATA[<p>又是一年校赛，和<a href="http://lihdd.net/2009/03/%E5%8F%88%E6%98%AF%E4%B8%80%E5%B9%B4%E6%A0%A1%E8%B5%9B/">去年</a>相比，今年的队友以及我的想法都很不一样了。</p>
<p>解题报告推荐看<a title="2010校赛 Judge’s View 和 解题报告" href="http://www.hhanger.com/blog/?p=438">hhanger裁判的版本</a>，十分好。我这里是流水账，不要在这里期待什么  <img src='http://lihdd.net/wp-includes/images/smilies/hmm.png' alt='.~.' class='wp-smiley' />  <span id="more-368"></span></p>
<p>早上的闹铃响了，意识到 8:45 是报名截止时间。速度赶去紫金港校区，结果发现来得比较早了，报名也不需要三个人的学生证，队友 asmn 准备吃完午饭再过来  <img src='http://lihdd.net/wp-includes/images/smilies/sigh.png' alt=':sigh:' class='wp-smiley' />  。很快找到了 moondy 一行人，一起去吃早饭，看来没有在玉泉校区解决早饭是明智的啊。</p>
<p>抽签是 007 号，还在用 CRT 显示器的一个机房，不过距离打印机特别近。学校的机器一如既往地存在着 Netbeans 3.x，试验了 Java， Dev-cpp 和 IE 浏览器没有问题之后，又玩了玩 cygwin。大概我们试的东西有些多，我到其他机房去串门的时候，认识的人已经很少了 <img src='http://lihdd.net/wp-includes/images/smilies/angry.png' alt='):' class='wp-smiley' />  </p>
<p>我觉得比赛的时候喝水比较重要，asmn 可能会没有准备齐全就赶过来，就去超市买了一些饮料和三支笔。回到 218 之后看着 <a href="http://watashi.ws/blog/">watashi</a> 在笔记本上玩游戏，仰慕之中很快眼花了，睡了一会儿。醒来的时候大家就都到齐了，很快进入了赛场。赛场外围有非常多的粉红色气球，是 A，想必这一题必须很简单了吧。</p>
<p>moondy 带去了 vls 的吉祥物，看起来很可爱的样子，不知道有没有被拍下来。赛后 asmn 好奇起来，去扒吉祥物的衣服，被 moody 制止了 -_-</p>
<p>比赛开始后，我填写了登陆信息，设置好 Dev-cpp，然后 moondy 说 A 题不会做，好在 asmn 看过后很快秒杀了。<a href="http://wyest.blogbus.com/">lam</a> 送来了第一个气球，大家都比较兴奋。接着 moondy 把 I 题秒杀了，我却还在读中间的三道题，我发现 E 题很容易的样子，写了一半发现输入中的 t1 可能是无序的，然后引入了 set，虽然这时候我觉得题目可能会有两种理解，不过交过发现 AC 后就没有继续管它了  <img src='http://lihdd.net/wp-includes/images/smilies/tongue.png' alt=':p' class='wp-smiley' />  </p>
<p>接着是 asmn 搞定了一道难题 G，虽然这次在三人检查下没有出现以前忘记加 <code>#include</code> 而 CE 的情况，但是却因为没有注释掉 <code>freopen</code> 而悲剧了一次 -,- </p>
<p>然后 moondy 很快搞定了 B，我觉得是比较需要人肉的题，真的太快了。这次是 LinYue 送来了气球，说“还剩一题”，那道题显然是 D，我自己对 D 的拙见是倘若只有不到 8 个 Case，那么一定可以过的，不过罚时可能难看一些了 -,- 三十个 Case 就算了。</p>
<p>下面大家就是去 yy 剩下的题目了，我觉得 H 的题目描述很不清楚，moondy 也有同感，但是 hhanger 裁判 No response，原来没有看过 Sample 是不会明白的，觉得可以做的样子，但是还有没看的题，moondy 介绍了 C，我觉得好像可以做的样子，但是具体怎么还做不确定。听到对面的队伍在讨论 D，我转过头看了看 asmn，也在笑，觉得很开怀。</p>
<p>接着，我想到了一种枚举方法，认为 C 可以做了，不过有一点担心会 TLE，和 asmn 讨论了一下，确认了算法的正确性，不过在许多细节上要很小心，很多 +1 和 -1 的问题。对 H 我也有了一些想法，moondy 也对 F 比较有想法，讨论后决定我写 C，moondy 写 F，asmn 写 H。接着就是三个人不断地写、调试三道题，打印了很多草稿纸。moondy 率先把 F 过了，我在想一些细节问题，接着 C 和 H 都相继 Wrong Answer 了，这时候大家有些沮丧，大概也有些疲劳了吧，会有各种想不清楚和低级错误。我相信 C 既然没有 TLE 的话一定是可以搞定的，moondy 和 asmn 发现 H 算法想得简单了，看起来是来不及改了，只有 C 有希望了，压力好大 -,- 突然 moondy 发现有一句 if 很奇怪，我一看，原来是之前修改代码的时候漏掉了这里，果断搞定，在最后十分钟内过了 C <img src='http://lihdd.net/wp-includes/images/smilies/very_happy.png' alt='^_^' class='wp-smiley' />  还有最后的 007 分钟，asmn 象征性地交了一个 D，从 ranklist 看来，其他队看起来没有保留的题目了，很欢喜。想必大家都觉得不错吧，无论是最后的成绩或是题目本身来说。</p>
<p>皆大欢喜的背后，还是有许多可以改进的地方的，不过每次具体情况都不一样，这次觉得要注意问题A，也许下次比赛的时候就会发生问题B，所以不多说什么了，经验是慢慢积累的。现在我看来，比赛等各种活动的意义除了对经验和实力的影响，更重要的地方在于人与人的互动，正如谷歌曾经用的愚人节广告词：“没人没乐趣，有人有真谛”，很高兴能处在这样一个和谐的团体，感谢每一个人。最后，bg 会有的  <img src='http://lihdd.net/wp-includes/images/smilies/wink.png' alt='^_.' class='wp-smiley' />  </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=Av44h3m6a_Q:s1FptU9nNlw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=Av44h3m6a_Q:s1FptU9nNlw:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/Av44h3m6a_Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/04/university-acm-contest-2010/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>四月二日的愚人节</title>
		<link>http://lihdd.net/2010/04/fools-day-on-april-2/</link>
		<comments>http://lihdd.net/2010/04/fools-day-on-april-2/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 12:13:09 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[festival]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=362</guid>
		<description><![CDATA[虽然是四月二日了，但是别像我一样，以为是四月二日就掉以轻心啊： 为了避免尴尬气氛，我决定把使用的头像图片换掉，更新成右上角的那张。作为老牌忠实的稻米，负责任地说一句广告：慕容引刀的画真的很不错。]]></description>
			<content:encoded><![CDATA[<p><a href="http://lihdd.net/wp-content/uploads/2010/04/swing_girl_export_120x120_border_blurred.png"><img class="alignright size-full wp-image-364" title="swing_girl_export_120x120_border_blurred" src="http://lihdd.net/wp-content/uploads/2010/04/swing_girl_export_120x120_border_blurred.png" alt="" width="120" height="120" /></a>虽然是四月二日了，但是别像我一样，以为是四月二日就掉以轻心啊：<span id="more-362"></span></p>
<div id="attachment_363" class="wp-caption alignnone" style="width: 426px"><a href="http://lihdd.net/wp-content/uploads/2010/04/april_fool_in_lua_list.png"><img class="size-full wp-image-363 " title="april_fool_in_lua_list" src="http://lihdd.net/wp-content/uploads/2010/04/april_fool_in_lua_list.png" alt="" width="416" height="343" /></a><p class="wp-caption-text">愚人节不该是四月二号吗，咦？！</p></div>
<p>为了避免尴尬气氛，我决定把使用的头像图片换掉，更新成右上角的那张。作为老牌忠实的稻米，负责任地说一句广告：<a href="http://blog.sina.com.cn/daodaodog">慕容引刀</a>的画真的很不错。</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=q-quSOrVtg8:UU-R7CTPhSU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=q-quSOrVtg8:UU-R7CTPhSU:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/q-quSOrVtg8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/04/fools-day-on-april-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于 ibus-sogoupycc 的扩展</title>
		<link>http://lihdd.net/2010/03/ibus-sogoupycc-extensions/</link>
		<comments>http://lihdd.net/2010/03/ibus-sogoupycc-extensions/#comments</comments>
		<pubDate>Thu, 18 Mar 2010 12:06:19 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Config]]></category>
		<category><![CDATA[Script]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[ibus]]></category>
		<category><![CDATA[ibus-sogoupycc]]></category>
		<category><![CDATA[lua]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=340</guid>
		<description><![CDATA[本来想把一些示例放在项目的 wiki 页上的，但是我还想说一些其他的闲话，而且目前扩展虽然有一些实用性了，却缺乏执行保护，可以把输入法弄得不稳定，所以这些内容就放到这里好了。如果你只想看看如何使用输入法的扩展，请向下找到 表情后从那里开始看。 似乎扩展是很流行的样子，各种浏览器，foobar2000，谷歌拼音，WPS，都可以用扩展。 其中，有的软件成功了，令人爱不释手，比如像 Firefox，foobar2000。有的软件却没有因为扩展成功，比如谷歌拼音。或者说扩展没有给人带来好感，比如 IE 浏览器。 我觉得作为一个支持扩展的软件，最重要的就是扩展要比较有用，可以做一些事情，这一点上谷歌拼音做得就不好，由于扩展而变得比较成功的软件在这方面做得都比较好。其次，扩展要容易开发，再往后，出于安全的考虑，扩展的能力要受到约束。这两点 IE 相比 Firefox 就弱了一些，不过 Firefox 的扩展写起来还是挺麻烦的，比如其中的多国语言化就非常麻烦，对于不同的地方要使用不同的方法，总共有三种。而由于 Firefox 的灵活性，出现了 Mozilla Jetpack 和 GreaseMonkey 等，都可以让扩展写起来方便一些。 在很长的一段时间内，我觉得编写软件，技术含量是最重要的， 一个更好的算法可以带来更快的速度，或者更好的结果，当然用户体验就会好。但是现在看法有些改变，因为目前，很多东西不是需要从头做起的，除非出于学习、版权目的，或者是原先的项目代码烂到不能看而没法维护，没有必要重新实现别人已经实现的东西。大部分软件应该在乎实用性，在不违反版权的情况下，尽量使用已有的东西。 从一开始，我觉得 ibus-sogoupycc 这样一个输入法的技术含量肯定不如 sunpinyin，Linux 下的输入法用 sunpinyin 就不错了，一度怀疑是否要有将 ibus-sogoupycc 写下去的必要。但是现在，我觉得是有必要的，因为在中国大部分有网络的地方，这样一个输入法用起来是更舒服的，至少对我自己来说。 出于同样的实用性的考虑，我提供了输入法扩展能力。本来我想提供一个完全兼容谷歌拼音的接口，但是后来觉得谷歌拼音的扩展接口设计得并不好，和目前输入法的无需选词流畅输入有冲突，没有遵循的必要。 开头提到的这个表情在这里： ，不难找吧。 扩展的设置应该放在用户配置文件中，目前添加一个扩展的方法是： ime.register_command&#40;key, modifiers, caption, script&#41; 这里，key 和 modifiers 都是数字类型，后两者是字符串类型。 修改用户配置文件后一般要重新启动输入法才能生效，可以右击任务栏上的 ibus 图标，选择重新启动。 Hello world 下面的代码注册了一个用 Alt + H [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://lihdd.net/wp-content/uploads/2010/03/extensions.png" alt="" title="extensions" width="100" height="125" class="alignright size-full wp-image-344" />本来想把一些示例放在项目的 wiki 页上的，但是我还想说一些其他的闲话，而且目前扩展虽然有一些实用性了，却缺乏执行保护，可以把输入法弄得不稳定，所以这些内容就放到这里好了。如果你只想看看如何使用输入法的扩展，请向下找到  <img src='http://lihdd.net/wp-includes/images/smilies/wink.png' alt='^_.' class='wp-smiley' />   表情后从那里开始看。</p>
<p>似乎扩展是很流行的样子，各种浏览器，foobar2000，谷歌拼音，WPS，都可以用扩展。</p>
<p>其中，有的软件成功了，令人爱不释手，比如像 Firefox，foobar2000。有的软件却没有因为扩展成功，比如谷歌拼音。或者说扩展没有给人带来好感，比如 IE 浏览器。<span id="more-340"></span></p>
<p>我觉得作为一个支持扩展的软件，最重要的就是扩展要比较有用，可以做一些事情，这一点上谷歌拼音做得就不好，由于扩展而变得比较成功的软件在这方面做得都比较好。其次，扩展要容易开发，再往后，出于安全的考虑，扩展的能力要受到约束。这两点 IE 相比 Firefox 就弱了一些，不过 Firefox 的扩展写起来还是挺麻烦的，比如其中的多国语言化就非常麻烦，对于不同的地方要使用不同的方法，总共有三种。而由于 Firefox 的灵活性，出现了 <a href="https://jetpack.mozillalabs.com/">Mozilla Jetpack</a> 和 <a href="https://addons.mozilla.org/firefox/addon/748">GreaseMonkey</a> 等，都可以让扩展写起来方便一些。</p>
<p>在很长的一段时间内，我觉得编写软件，技术含量是最重要的， 一个更好的算法可以带来更快的速度，或者更好的结果，当然用户体验就会好。但是现在看法有些改变，因为目前，很多东西不是需要从头做起的，除非出于学习、版权目的，或者是原先的项目代码烂到不能看而没法维护，没有必要重新实现别人已经实现的东西。大部分软件应该在乎实用性，在不违反版权的情况下，尽量使用已有的东西。</p>
<p>从一开始，我觉得 ibus-sogoupycc 这样一个输入法的技术含量肯定不如 <a href="http://code.google.com/p/sunpinyin/">sunpinyin</a>，Linux 下的输入法用 sunpinyin 就不错了，一度怀疑是否要有将 ibus-sogoupycc 写下去的必要。但是现在，我觉得是有必要的，因为在中国大部分有网络的地方，这样一个输入法用起来是更舒服的，至少对我自己来说。<br />
<div id="attachment_347" class="wp-caption aligncenter" style="width: 266px"><img src="http://lihdd.net/wp-content/uploads/2010/03/ibus-sogoupycc-0.2.0_demo.gif" alt="" title="ibus-sogoupycc-0.2.0_demo" width="256" height="179" class="size-full wp-image-347" /><p class="wp-caption-text">使用信号很弱的无线网，输入起来感觉也不错</p></div></p>
<p>出于同样的实用性的考虑，我提供了输入法扩展能力。本来我想提供一个完全兼容谷歌拼音的接口，但是后来觉得谷歌拼音的扩展接口设计得并不好，和目前输入法的无需选词流畅输入有冲突，没有遵循的必要。</p>
<p><em>开头提到的这个表情在这里： <img src='http://lihdd.net/wp-includes/images/smilies/wink.png' alt='^_.' class='wp-smiley' />  ，不难找吧。</em></p>
<p>扩展的设置应该放在用户配置文件中，目前添加一个扩展的方法是：</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">ime.register_command<span style="color: #66cc66;">&#40;</span>key, modifiers, caption, script<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>这里，key 和 modifiers 都是数字类型，后两者是字符串类型。</p>
<p>修改用户配置文件后一般要重新启动输入法才能生效，可以右击任务栏上的 ibus 图标，选择重新启动。</p>
<p><strong>Hello world</strong><br />
下面的代码注册了一个用 Alt + H 可以激活的扩展，只要输入法被激活，无论处于中英文状态，都可以用这个热键运行这个扩展。</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;h&quot;</span><span style="color: #66cc66;">&#41;</span>:byte<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>, key.MOD1_MASK, <span style="color: #ff0000;">&quot;hello&quot;</span>, <span style="color: #ff0000;">&quot;ime.notify('hello world')&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>重新启动 ibus 之后，按下方形的扩展按钮(ibus-1.2.0.20090927 版本下，方形按钮会消失，这是 ibus 的已知问题，此时通过热键仍然可以运行扩展)，可以看到一个标题为 hello 的菜单项，单击它，就可以运行扩展。<br />
<div id="attachment_343" class="wp-caption aligncenter" style="width: 197px"><img src="http://lihdd.net/wp-content/uploads/2010/03/ime_extension_menu.png" alt="" title="ime_extension_menu" width="187" height="301" class="size-full wp-image-343" /><p class="wp-caption-text">输入法扩展菜单</p></div><br />
这里，第一个参数是按键，<code>("h"):byte()</code> 表示 h 的 ASCII 码，<code>"ime.notify('hello world')"</code> 是一段字符串表示的 lua 代码，它利用输入法提供的 <code>ime.notify</code> 方法显示了一些内容。</p>
<p><strong>插入系统时间</strong></p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">ime.register_command<span style="color: #66cc66;">&#40;</span>key.Shift_R, <span style="color: #cc66cc;">0</span>, <span style="color: #ff0000;">&quot;插入系统时间&quot;</span>, <span style="color: #ff0000;">&quot;ime.commit(os.date())&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>这里的 <code>ime.commit</code> 也是输入法提供的方法，用来直接向客户端程序输入文字，<code>os.date</code> 是 Lua 标准库函数。这段代码注册了一个用 右Shift 激活的插入系统时间的功能。</p>
<p>Lua 的标准库函数在扩展中都是可以用的，比如可以用 <code>os.execute('mousepad &#038;')</code> 在后台运行一个 mousepad。</p>
<p><strong>执行 Lua 代码</strong></p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'L'</span><span style="color: #66cc66;">&#41;</span>:byte<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>, key.SHIFT_MASK + key.MOD1_MASK ,
  <span style="color: #ff0000;">&quot;执行 Lua 代码&quot;</span>, <span style="color: #ff0000;">&quot;ime.execute('ime.notify('..ime.get_selection()..')')&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>这段代码注册了一个用 Shift + Alt + L 热键，把选中内容当做 Lua 脚本执行，并用桌面提示显示结果的扩展，这里因为有了 Shift 辅助键，所以要取大写字母 L 的 ASCII 码。其中使用方法 <code>ime.get_selection</code> 获得选定文字的内容，<code>ime.execute</code> 用来把一个字符串当做 Lua 脚本运行，双点号是字符串连接操作。</p>
<p>这个扩展可以比较有用，比如当选定 <code>315+23*6145</code> 这样的表达式之后，运行一下扩展就可以知道计算结果，也可以选定 <code>ime.VERSION</code> 这样的内部变量，查看其内容。甚至可以选定一段 <code>ime.register_command</code> 代码，动态添加扩展  <img src='http://lihdd.net/wp-includes/images/smilies/happy.png' alt='(:' class='wp-smiley' /> </p>
<p><strong>“回音”效果</strong><br />
不知道从什么地方开始流行这种效果，我想说明的是，声明一个函数并且在扩展中调用是可以的：</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;"><span style="color: #b1b100;">function</span> echo_effect<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #b1b100;">local</span> s <span style="color: #66cc66;">=</span> ime.get_selection<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #b1b100;">for</span> i <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span>, #s, <span style="color: #cc66cc;">3</span> <span style="color: #b1b100;">do</span> ime.commit<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>i <span style="color: #66cc66;">==</span> <span style="color: #cc66cc;">1</span> <span style="color: #b1b100;">and</span> <span style="color: #ff0000;">''</span> <span style="color: #b1b100;">or</span> <span style="color: #ff0000;">'，'</span><span style="color: #66cc66;">&#41;</span>..s:sub<span style="color: #66cc66;">&#40;</span>i<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">end</span>
<span style="color: #b1b100;">end</span>
ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'E'</span><span style="color: #66cc66;">&#41;</span>:byte<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>, key.SHIFT_MASK + key.CONTROL_MASK,
  <span style="color: #ff0000;">&quot;产生回音&quot;</span>, <span style="color: #ff0000;">&quot;echo_effect()&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>这里简单地使用了 3 个字节 作为步长，所以只能处理纯中文。对文字 &#8220;这是回音你懂吗&#8221; 使用这个扩展会得到：&#8221;这是回音你懂吗，是回音你懂吗，回音你懂吗，音你懂吗，你懂吗，懂吗，吗&#8221;  <img src='http://lihdd.net/wp-includes/images/smilies/sigh.png' alt=':sigh:' class='wp-smiley' />  </p>
<p><strong>全半角切换</strong><br />
输入法本身没有提供全半角切换功能，但是通过扩展可以实现类似功能：</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">ime.second_punc_map <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
<span style="color: #b1b100;">function</span> toggle_punc_map<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	ime.second_punc_map, ime.punc_map <span style="color: #66cc66;">=</span> ime.punc_map, ime.second_punc_map
	ime.apply_settings<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	ime.notify<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'已切换到'</span> .. <span style="color: #66cc66;">&#40;</span>ime.punc_map<span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'.'</span><span style="color: #66cc66;">&#93;</span> <span style="color: #b1b100;">and</span> <span style="color: #ff0000;">'全'</span> <span style="color: #b1b100;">or</span> <span style="color: #ff0000;">'半'</span><span style="color: #66cc66;">&#41;</span> ..<span style="color: #ff0000;">'角'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #b1b100;">end</span>
ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">','</span><span style="color: #66cc66;">&#41;</span>:byte<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>, key.CONTROL_MASK , <span style="color: #ff0000;">&quot;全半角切换&quot;</span>, <span style="color: #ff0000;">&quot;toggle_punc_map()&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>注册了 Ctrl + 逗号 作为切换热键，并会用桌面提示显示切换结果。</p>
<p><strong>全双拼切换</strong><br />
可以仿造上例写出：</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #ff0000;">&quot;全双拼切换&quot;</span>,
  <span style="color: #ff0000;">&quot;ime.use_double_pinyin = not ime.use_double_pinyin ime.apply_settings()&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>前面填写的两个 0 表示这个扩展没有热键，你也可以再加上一句 <code>ime.notify</code>，使得切换的时候有桌面提示。</p>
<p><strong>对缓存的操作</strong><br />
缓存是存在全局的 <code>request_cache</code> 中的，可以直接对其操作：</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;"><span style="color: #b1b100;">function</span> show_request_cache<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #b1b100;">for</span> i,v <span style="color: #b1b100;">in</span> <span style="color: #b1b100;">pairs</span><span style="color: #66cc66;">&#40;</span>request_cache<span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">do</span>
		ime.commit<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'&quot;'</span>..i..<span style="color: #ff0000;">'&quot; =&gt; &quot;'</span>..v..<span style="color: #ff0000;">'&quot;<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #b1b100;">end</span>
<span style="color: #b1b100;">end</span>
ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">0</span> , <span style="color: #ff0000;">&quot;查看缓存&quot;</span>, <span style="color: #ff0000;">&quot;show_request_cache()&quot;</span><span style="color: #66cc66;">&#41;</span>
ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">0</span> , <span style="color: #ff0000;">&quot;清空缓存&quot;</span>, <span style="color: #ff0000;">&quot;request_cache = {}&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>其中的 <code>ime.commit</code> 方法用来向客户端插入文本，还有一个方法是 <code>ime.request</code>，用来向输入法提交一个拼音请求，比如下面这段代码片段将向输入法提交《春晓》的拼音：</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;"><span style="color: #b1b100;">for</span> _, v <span style="color: #b1b100;">in</span> <span style="color: #b1b100;">pairs</span>
<span style="color: #66cc66;">&#123;</span><span style="color: #ff0000;">'chun mian bu jue xiao'</span>, <span style="color: #ff0000;">'chu chu wen ti niao'</span>,
 <span style="color: #ff0000;">'ye lai feng yu sheng'</span>, <span style="color: #ff0000;">'hua luo zhi duo shao'</span><span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">do</span>
	ime.request<span style="color: #66cc66;">&#40;</span>v<span style="color: #66cc66;">&#41;</span>
	ime.commit<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #b1b100;">end</span></pre></div></div>

<p><strong>给自己发送飞信</strong><br />
输入法全局配置文件默认加载了 <code>socket.http</code> 和 <code>socket.url</code> 模块，可以用它们来访问网络。</p>
<p>比如，下面的代码通过 <a href="http://api.bz/">api.bz</a> 这个在线接口把选定文字内容通过飞信发送给自己：</p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;"><span style="color: #b1b100;">function</span> send_sms<span style="color: #66cc66;">&#40;</span>content<span style="color: #66cc66;">&#41;</span>
	http.TIMEOUT <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">2</span>
	<span style="color: #b1b100;">local</span> res <span style="color: #66cc66;">=</span> http.request<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'https://sms.api.bz/fetion.php?username=15566119320&amp;password=nevermind&amp;sendto=15566119320&amp;message='</span>..url.escape<span style="color: #66cc66;">&#40;</span>content<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
	ime.notify<span style="color: #66cc66;">&#40;</span>res <span style="color: #b1b100;">or</span> <span style="color: #ff0000;">'飞信发送失败'</span>, content, <span style="color: #ff0000;">'info'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #b1b100;">end</span>
&nbsp;
ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'m'</span><span style="color: #66cc66;">&#41;</span>:byte<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>, key.CONTROL_MASK + key.MOD1_MASK, <span style="color: #ff0000;">&quot;飞信发送&quot;</span>, <span style="color: #ff0000;">&quot;send_sms(ime.get_selection())&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>以上填写的飞信用户名和密码皆为虚构，实际用的时候需要改一下。</p>
<p><strong>简繁体转换和翻译</strong><br />
使用 Google API 来翻译文字，从简体中文翻译成繁体中文就实现了转换成繁体  <img src='http://lihdd.net/wp-includes/images/smilies/happy.png' alt='(:' class='wp-smiley' /> </p>

<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;"><span style="color: #b1b100;">function</span> google_translate<span style="color: #66cc66;">&#40;</span>text, langpair<span style="color: #66cc66;">&#41;</span>
	<span style="color: #b1b100;">local</span> url <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&amp;q='</span>..url.escape<span style="color: #66cc66;">&#40;</span>text<span style="color: #66cc66;">&#41;</span>..<span style="color: #ff0000;">'&amp;langpair='</span>..url.escape<span style="color: #66cc66;">&#40;</span>langpair<span style="color: #66cc66;">&#41;</span>
	http.TIMEOUT <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span>
	<span style="color: #b1b100;">local</span> res <span style="color: #66cc66;">=</span> http.request<span style="color: #66cc66;">&#40;</span>url<span style="color: #66cc66;">&#41;</span>
	<span style="color: #b1b100;">if</span> res <span style="color: #b1b100;">then</span> res <span style="color: #66cc66;">=</span> res:match<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'&quot;translatedText&quot;:&quot;(.-)&quot;}'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">end</span>
	<span style="color: #b1b100;">return</span> <span style="color: #b1b100;">tostring</span><span style="color: #66cc66;">&#40;</span>res <span style="color: #b1b100;">or</span> text<span style="color: #66cc66;">&#41;</span>
<span style="color: #b1b100;">end</span>
&nbsp;
ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'t'</span><span style="color: #66cc66;">&#41;</span>:byte<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>, key.CONTROL_MASK + key.MOD1_MASK ,
  <span style="color: #ff0000;">&quot;转换成繁体&quot;</span>, <span style="color: #ff0000;">&quot;ime.commit(google_translate(ime.get_selection(), 'zh-CN|zh-TW'))&quot;</span><span style="color: #66cc66;">&#41;</span>
ime.register_command<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'e'</span><span style="color: #66cc66;">&#41;</span>:byte<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>, key.CONTROL_MASK + key.MOD1_MASK ,
  <span style="color: #ff0000;">&quot;翻译成英文&quot;</span>, <span style="color: #ff0000;">&quot;ime.commit(google_translate(ime.get_selection(), 'zh-CN|en'))&quot;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p><strong>写在最后</strong></p>
<p>这是一个悲剧。</p>
<p>Lua 作者根本不相信多线程，原因是现在的主流语言中连 <code>a = a + 1</code> 都不是原子的，谈什么多线程呢？</p>
<p>我曾经做过一些尝试，确实让程序多线程地执行 Lua 代码，又共享一些全局数据，不是轻松的事情。我也想到一些解决办法，但是都太麻烦了，于是就偷懒不管那么多了。</p>
<p>这有什么影响呢？影响就是目前输入法执行 Lua 代码是单线程的，扩展中的 Lua 代码会造成阻塞。在有网络请求等操作的时候，要注意控制超时，否则程序可能被认为没有响应了，各种死法都有可能出现  <img src='http://lihdd.net/wp-includes/images/smilies/hmm.png' alt='.~.' class='wp-smiley' />  </p>
<p>目前输入法的自由程度到了可以随意 AOE，比如用 <code>os.execute('pkill Xorg')</code>，就可以干掉许多无辜者。正所谓权力越大，责任越大。到底安全与否，就看扩展中的代码自我约束得如何了  <img src='http://lihdd.net/wp-includes/images/smilies/meeh.png' alt='._.' class='wp-smiley' />  </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=YwUmcvV-KEs:rsZ6Hq4o1v8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=YwUmcvV-KEs:rsZ6Hq4o1v8:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/YwUmcvV-KEs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/03/ibus-sogoupycc-extensions/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>一个 NFA 引发的血案</title>
		<link>http://lihdd.net/2010/03/one-nfa-related-homework-exercise/</link>
		<comments>http://lihdd.net/2010/03/one-nfa-related-homework-exercise/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 01:49:10 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[dfa]]></category>
		<category><![CDATA[nfa]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=331</guid>
		<description><![CDATA[引发血案的 NFA 就是下面这个，来自最近的《编译原理》作业的一道题： 把 NFA 变成 DFA 是有明确的办法的。只是，如果试着画一画上面这个图，就会发现另外一个问题，到底要画多少条线，几个圈，会不会把自己绕糊涂呢 于是我就想去找一个程序，可以自动完成这种枯燥的 NFA 到 DFA 的转换工作 。在 pluskid 的这篇日志里面看到了 reAnimator 这个在线工具，它可以把一串正则表达式的NFA和最简的DFA画出来。不过只能处理简单的情况，像上面那样 (a&#124;b)*a(a&#124;b)(a&#124;b)(a&#124;b)(a&#124;b) 的表达式根本没法画出图来 reAnimator 作者的博客上面介绍了它的实现，但具体细节并没有公开，只好再去找其他的工具…… 直觉说 Mathematica 很可能提供了相关的功能。很遗憾找了半天没找到内建的和 FA 有关的函数，惊喜的是在网上有一个叫做 Finite Automata 的 Mathematica 包，看起来功能全面，挺不错。但是用一下就发现它的实现（比如，NFA 到 DFA 的转换）是有错误的，果断放弃 再找到的就是一个叫做 Visual Automata Simulator 的软件，提供了 NFA 到 DFA 转换的功能，看起来很不错。用它完成了转换工作，血案由此产生了：一共画出来了 32 个状态和 64 条边…… 经过简单的测试， VAS 软件并不会做最小化 DFA 的工作，那么上面的结果可不可以再简单一点呢？比如下面的这个 DFA： 可以被最小化到： [...]]]></description>
			<content:encoded><![CDATA[<p>引发血案的 NFA 就是下面这个，来自最近的《编译原理》作业的一道题：</p>
<div id="attachment_306" class="wp-caption aligncenter" style="width: 528px"><img class="size-full wp-image-306  " title="ex_nfa2dfa" src="http://lihdd.net/wp-content/uploads/2010/03/ex_nfa2dfa.png" alt="ex_nfa2dfa" width="518" height="97" /><p class="wp-caption-text">将这个 NFA 转化成 DFA</p></div>
<p>把 NFA 变成 DFA 是有明确的办法的。只是，如果试着画一画上面这个图，就会发现另外一个问题，到底要画多少条线，几个圈，会不会把自己绕糊涂呢  <img src='http://lihdd.net/wp-includes/images/smilies/hmm.png' alt='.~.' class='wp-smiley' /><br />
<span id="more-331"></span><br />
于是我就想去找一个程序，可以自动完成这种枯燥的 NFA 到 DFA 的转换工作 。在 <a href="http://blog.pluskid.org/?p=285">pluskid 的这篇日志</a>里面看到了 <a href="http://osteele.com/tools/reanimator/">reAnimator</a> 这个在线工具，它可以把一串正则表达式的NFA和最简的DFA画出来。不过只能处理简单的情况，像上面那样</p>
<pre>(a|b)*a(a|b)(a|b)(a|b)(a|b)</pre>
<p>的表达式根本没法画出图来  <img src='http://lihdd.net/wp-includes/images/smilies/what.png' alt='o.o' class='wp-smiley' />   reAnimator 作者的博客上面介绍了它的实现，但具体细节并没有公开，只好再去找其他的工具……</p>
<p>直觉说 <em>Mathematica</em> 很可能提供了相关的功能。很遗憾找了半天没找到内建的和 FA 有关的函数，惊喜的是在网上有一个叫做 <a href="http://library.wolfram.com/infocenter/Demos/75/">Finite Automata</a> 的 <em>Mathematica</em> 包，看起来功能全面，挺不错。但是用一下就发现它的实现（比如，NFA 到 DFA 的转换）是有错误的，果断放弃  <img src='http://lihdd.net/wp-includes/images/smilies/sigh.png' alt=':sigh:' class='wp-smiley' /> </p>
<p>再找到的就是一个叫做 <a href="http://www.cs.usfca.edu/~jbovet/vas.html">Visual Automata Simulator</a> 的软件，提供了 NFA 到 DFA 转换的功能，看起来很不错。用它完成了转换工作，血案由此产生了：一共画出来了 32 个状态和 64 条边……</p>
<p>经过简单的测试， VAS 软件并不会做最小化 DFA 的工作，那么上面的结果可不可以再简单一点呢？比如下面的这个 DFA：</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-318" title="dfa_normal" src="http://lihdd.net/wp-content/uploads/2010/03/dfa_normal.png" alt="dfa_normal" width="330" height="239" /></p>
<p>可以被最小化到：</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-319" title="dfa_minimized" src="http://lihdd.net/wp-content/uploads/2010/03/dfa_minimized.png" alt="dfa_minimized" width="286" height="240" /></p>
<p style="text-align: left;">试试看？我在 VAS 的代码上加了课本上介绍的最小化 DFA 的方法，结果对刚才的 64 条边的图毫无效果  <img src='http://lihdd.net/wp-includes/images/smilies/meeh.png' alt='._.' class='wp-smiley' /> </p>
<p style="text-align: left;">那么就把这个图打印出来吧，都到这一步了，写一个“略”在作业本上不太好吧。不过，VAS 自己没有自动排版功能，线条和圆圈画得非常乱。在 VAS 中不难实现一个导出 dot 文件的功能，然后就可以用 <a href="http://www.graphviz.org/">graphviz</a> 来排版了  <img src='http://lihdd.net/wp-includes/images/smilies/happy.png' alt='(:' class='wp-smiley' /> </p>
<p>最后排出来大概是<a href="http://lihdd.net/wp-content/uploads/2010/03/dfa_by_dot.svg">这个样子</a>，还是挺乱的样子，也许自动排版成这个样子算是很好了吧。</p>
<p>我觉得 VAS 这个工具还是挺好的，在官方 1.2.2 版本上我添加了 DFA 最小化和导出到 dot 文件两个功能，擅自把版本号改成了 1.2.3。放在这里，也许什么时候会被用一下：</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/03/vas.jar">Visual Automata Simulator 1.2.3 (jar)</a> <a href="http://lihdd.net/wp-content/uploads/2010/03/vas_src.zip">(源代码)</a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=6O7aZ2sVIq4:s0AC_HvddfY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=6O7aZ2sVIq4:s0AC_HvddfY:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/6O7aZ2sVIq4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/03/one-nfa-related-homework-exercise/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>ibus-sogoupycc，我的输入法，我的寒假</title>
		<link>http://lihdd.net/2010/03/my-work-on-ibus-sogoupycc/</link>
		<comments>http://lihdd.net/2010/03/my-work-on-ibus-sogoupycc/#comments</comments>
		<pubDate>Sun, 28 Feb 2010 17:22:46 +0000</pubDate>
		<dc:creator>quark</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[ibus-sogoupycc]]></category>
		<category><![CDATA[ime]]></category>
		<category><![CDATA[sogou]]></category>

		<guid isPermaLink="false">http://lihdd.net/?p=322</guid>
		<description><![CDATA[五月天的 “突然好想你” MV 中的有两段对着屏幕录的输入中文的过程，看起来输入很方便，由此，我对台湾的输入法产生了兴趣。 由于天之痕而喜欢上轩辕剑系列的我，在云之遥上市之后，看着台湾玩家慢慢地通关，和他们聊起了输入法，被告知无虾米输入法目 前是超过新仓颉，最流行，最好学，最快的输入法，连幼儿园小朋友都在学。 难以想象把注音、字形、英文单词混合编码的输入法是什么样子，但无虾米输入法就是这样的输入法，它还是拥有 Windows 98 时代的灰色界面，并收费的繁体世界最流行的输入法。我尝试练习一段时间之后，聚精会神地输入最基本的字根的速度只有双拼的四分之一，又由于繁体字和简体字 有很大区别，注音和拼音也有区别，决定放弃无虾米。 拼音类的输入法的通病，重码很多，一不留神就会输入错字。我想去尝试一些其他的形码输入法。简体的形码输入，比较流行的就是五笔和郑码，虽然似乎五 笔的名气大一些，但是郑码看起来更加好，我决定在寒假期间学会它。 世事万变，突然有一天，我收到一用户的邮件，其中提到了对 ibus-sogoupycc 的建议，还指出了几处错误。本来觉得用 Linux 的人就很少了，用双拼的人就更少了，同时使用 Linux、双拼，还要是 ibus 的用户也许就只有十几个。但是那封邮件让我觉得世界上这样的用户多了起来，这个几个月没有变化的项目是时候去动一下了。我重新考虑了形码输入法是不是值得 去学，认为不用选词、两个键一个字、不用按空格确认的双拼肯定比形码快不少。至于云服务器识别错误的汉字，我想到了微软拼音的“纠正”功能，一种不会打扰正常输入而提供纠正错字的办法。于是我决定在寒假期间实现这些想法，并放弃学习形码输入法。 说到微软拼音，我一直觉得它是输入法界最有技术含量、最规范的。它规范到了不愿意接受网络词汇（2010版本之前），就让其它的拼音输入法有了可乘 之机。微软拼音的整句输入感觉很舒服，输入完拼音之后，不用多余的空格确认，可以按一个标点，表示确认输入并加上这个标点。写 ibus-sogoupycc 的时候我参照了微软拼音的一些行为，比如：选中文字后，可以将文字转换回会拼音，再开始选词，用于纠正错字；使用双拼的时候，屏幕显示的是全拼的提示。 主流拼音输入法需要用数字键选词，而数字键按起来不方便，这就有了用空格， Ctrl，Alt 等键来选词的特殊需求。那么如果用 asdfjkl 来选词，不就会更好吗？ ibus-sogoupycc 默认就是这样，为了区分需选词按键和拼音按键，输入完拼音后需要按下 Tab 键，才开始选词，用 h 和 g 键翻页。 没想到，真正开始写程序之后，很快就进入了令人寝食难安的调试周。程序似乎在各个地方都能出错，在我的代码外。使用了各种正道歪道，无济于事。多线 程程序，你也许是有体会的。几天后实在找不到原因，就在 ibus-devel 讨论组提问，感谢 P.Huang ，我知道了像 glib 和 dubs 这样的东西并不愿意知道目前运行的程序是多线程的，你需要调用它们的函数通知一下才可以。相比之下 glibc 就很听话，使用 `-pthread` 编译参数就可以使得大量的 glibc 调用变成可重入的版本。 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://lihdd.net/wp-content/uploads/2010/03/miss_you_suddenly_mv-may_day.png"><img class="alignright size-full wp-image-323" title="miss_you_suddenly_mv-may_day" src="http://lihdd.net/wp-content/uploads/2010/03/miss_you_suddenly_mv-may_day.png" alt="miss_you_suddenly_mv-may_day" width="120" height="103" /></a>五月天的 “突然好想你” MV 中的有两段对着屏幕录的输入中文的过程，看起来输入很方便，由此，我对台湾的输入法产生了兴趣。</p>
<p>由于天之痕而喜欢上轩辕剑系列的我，在云之遥上市之后，看着<a href="http://zh-tw.justin.tv/nagisa36605">台湾玩家</a>慢慢地通关，和他们聊起了输入法，被告知<a href="http://boshiamy.com/">无虾米输入法</a>目 前是超过新仓颉，最流行，最好学，最快的输入法，连幼儿园小朋友都在学。<span id="more-322"></span></p>
<p>难以想象把注音、字形、英文单词混合编码的输入法是什么样子，但无虾米输入法就是这样的输入法，它还是拥有 Windows 98  时代的灰色界面，并收费的繁体世界最流行的输入法。我尝试练习一段时间之后，聚精会神地输入最基本的字根的速度只有双拼的四分之一，又由于繁体字和简体字 有很大区别，注音和拼音也有区别，决定放弃无虾米。</p>
<p>拼音类的输入法的通病，重码很多，一不留神就会输入错字。我想去尝试一些其他的形码输入法。简体的形码输入，比较流行的就是五笔和郑码，虽然似乎五 笔的名气大一些，但是郑码看起来更加好，我决定在寒假期间学会它。</p>
<p>世事万变，突然有一天，我收到一用户的邮件，其中提到了对 <a href="http://code.google.com/p/ibus-sogoupycc/">ibus-sogoupycc</a> 的建议，还指出了几处错误。本来觉得用 Linux 的人就很少了，用双拼的人就更少了，同时使用 Linux、双拼，还要是 ibus  的用户也许就只有十几个。但是那封邮件让我觉得世界上这样的用户多了起来，这个几个月没有变化的项目是时候去动一下了。我重新考虑了形码输入法是不是值得 去学，认为不用选词、两个键一个字、不用按空格确认的双拼肯定比形码快不少。至于云服务器识别错误的汉字，我想到了微软拼音的“纠正”功能，一种不会打扰正常输入而提供纠正错字的办法。于是我决定在寒假期间实现这些想法，并放弃学习形码输入法。</p>
<div id="attachment_327" class="wp-caption aligncenter" style="width: 400px"><a href="http://lihdd.net/wp-content/uploads/2010/03/ibus-sogoupycc-demo.gif"><img class="size-full wp-image-327" title="ibus-sogoupycc-demo" src="http://lihdd.net/wp-content/uploads/2010/03/ibus-sogoupycc-demo.gif" alt="ibus-sogoupycc-demo" width="390" height="124" /></a><p class="wp-caption-text">不用选词的双拼</p></div>
<p>说到微软拼音，我一直觉得它是输入法界最有技术含量、最规范的。它规范到了不愿意接受网络词汇（2010版本之前），就让其它的拼音输入法有了可乘 之机。微软拼音的整句输入感觉很舒服，输入完拼音之后，不用多余的空格确认，可以按一个标点，表示确认输入并加上这个标点。写  ibus-sogoupycc   的时候我参照了微软拼音的一些行为，比如：选中文字后，可以将文字转换回会拼音，再开始选词，用于纠正错字；使用双拼的时候，屏幕显示的是全拼的提示。</p>
<p>主流拼音输入法需要用数字键选词，而数字键按起来不方便，这就有了用空格， Ctrl，Alt 等键来选词的特殊需求。那么如果用 asdfjkl  来选词，不就会更好吗？ ibus-sogoupycc 默认就是这样，为了区分需选词按键和拼音按键，输入完拼音后需要按下 Tab  键，才开始选词，用 h 和 g 键翻页。</p>
<p><a href="http://lihdd.net/wp-content/uploads/2010/03/ibus-sogoupycc.png"><img class="alignright size-full wp-image-324" title="ibus-sogoupycc" src="http://lihdd.net/wp-content/uploads/2010/03/ibus-sogoupycc.png" alt="ibus-sogoupycc" width="48" height="48" /></a>没想到，真正开始写程序之后，很快就进入了令人寝食难安的调试周。程序似乎在各个地方都能出错，在我的代码外。使用了各种正道歪道，无济于事。多线 程程序，你也许是有体会的。几天后实在找不到原因，就在 ibus-devel 讨论组提问，感谢 P.Huang ，我知道了像 glib 和  dubs 这样的东西并不愿意知道目前运行的程序是多线程的，你需要调用它们的函数通知一下才可以。相比之下 glibc 就很听话，使用  `-pthread` 编译参数就可以使得大量的 glibc 调用变成可重入的版本。</p>
<p>让我好几天辗转反复的问题居然就这样添加两个函数调用解决了，虽不甘心，但确实可以继续做下去了。寒假最后的两天，原来以为会比较难做的通过外部词 库选词，实际上比较容易就完成了。2月27日，我在<a href="http://code.google.com/p/ibus-sogoupycc/downloads/">项目的  Download 页</a>放上了 0.1.0 的版本以及 Archlinux 用的安装包，更新了许多 wiki  页。但是随后我自己就发现了几个问题，不乏有低级错误。2月28日，我的一个好朋友过生日的这一天，我修正了我自己发现的那些问题，并通过测试，确保没有 问题。把版本更新到了 0.1.1 ，更新了 wiki 页。至此，我觉得是比较好了。</p>
<p>以前，用 Windows 的时候总是感觉到输入法比 Linux 好太多了，现在感觉倒过来了  <img src='http://lihdd.net/wp-includes/images/smilies/happy.png' alt='(:' class='wp-smiley' /> </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lihdd?a=hekVroVyTrU:A6Aqm4or7v0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lihdd?i=hekVroVyTrU:A6Aqm4or7v0:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/lihdd/~4/hekVroVyTrU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://lihdd.net/2010/03/my-work-on-ibus-sogoupycc/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 1.803 seconds. --><!-- Cached page generated by WP-Super-Cache on 2012-02-01 02:21:12 -->

