<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>静养心智-动抒豪情™ - 王聪明的日志 &#187; Geek Tweak</title>
	<atom:link href="http://wangcongming.info/category/geek-tweak/feed/" rel="self" type="application/rss+xml" />
	<link>http://wangcongming.info</link>
	<description>灵 动 生 活　　点 滴 感 悟</description>
	<lastBuildDate>Sun, 19 Feb 2012 18:04:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>我是怎么管理密码的</title>
		<link>http://wangcongming.info/2011/12/%e6%88%91%e6%98%af%e6%80%8e%e4%b9%88%e7%ae%a1%e7%90%86%e5%af%86%e7%a0%81%e7%9a%84/</link>
		<comments>http://wangcongming.info/2011/12/%e6%88%91%e6%98%af%e6%80%8e%e4%b9%88%e7%ae%a1%e7%90%86%e5%af%86%e7%a0%81%e7%9a%84/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 16:59:03 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[1Password]]></category>
		<category><![CDATA[KeePass]]></category>
		<category><![CDATA[sha1]]></category>
		<category><![CDATA[密码]]></category>

		<guid isPermaLink="false">http://wangcongming.info/?p=1192</guid>
		<description><![CDATA[应推友要求，介绍下我现在是怎么管理密码的 :) 。 这个方法不是我首创，我也是受别人启发，但可以简单论述下为什么这个方法好~。 &#160; 这个问题的背景，是这个国家的互联网行业，开发者素养差、管理者道德低的普遍现状（当然，国外也有很多不负责任/不懂如何负责任的网站）。我们对于所有网络服务，普遍处于不信任的状态（特别是国内还多了官僚监管这一层），但是有的时候又不得不用。那么，作为用户，我们如何保护自己的信息安全（这里只谈密码）？ &#160; 理想状况： 每个网站都使用不同的密码； 而且都很复杂。 2 保证了如果某个网站技术不太行，保护措施做得不够好，你的密码也不会轻易被破解；而 1 保证了即使在极端情况下，也只会被泄露这一个网站的密码，不影响你在其它网站上的账户。 &#160; 然而，要用人脑来记忆不同网站的不同的复杂的密码，显然是不可行的。所以我们要借助一些辅助措施。有一类软件提供这样的功能，需要的时候，它可以帮你生成一个随机的很复杂的密码，同时把它存起来。你可以注明这是什么网站的密码，然后用一个主密码把这些随机密码都加密起来。所以，软件负责记住不同网站不同的复杂密码，而我们人脑只需要记住一个主密码。 &#160; 这是个好主意，但是还不够好。问题在于那些不同网站的密码都是随机生成的，这也就注定了我们的焦虑（我们失去了把控，只能完全依赖于一个黑盒）。我们总会担心记录弄丢了、损坏了、出门在外忘带了（同步？没网络呢、别人的机器呢？），或者某种平台这个软件不支持等等。总之，我们被 lock-in 了！ &#160; 我现在的方法是，不使用随机密码，而是用主密码+网站名，然后算 sha1。即： $ sha1sum password+csdn ^D 对，出来一串“乱码”，就用这串乱码做密码。这样做的好处，只要密码后面的网站名不同，生成的“乱码”就完全不同，即使有几个网站同时不靠谱、同时把你的密码（即刚刚生成的“乱码”）泄露了，你的主密码是绝对安全的（当然，要搞复杂一点）。另一方面，你知道这些“乱码”是怎么生成的，所以你不再依赖于某一个单一的软件，因为 sha1 算法是整个计算机系统的重要基础设施之一，哪里都有它的踪影、久经考验。 &#160; 哦，你会说，这是程序员的玩意儿，非程序员怎么办？非也，算 sha1 的小软件，可是比密码管理软件分布广泛多了。Windows/Linux/Mac OS、手机、平板⋯哪个平台上没有？不但有，而且很简单、很好用，绿色环保！就算没有，照着公开的算法写一个也不是什么难事。 所以，我们与其小心翼翼地备一个密码管理系统，不如大大方方地随便哪放一个算 sha1 的小软件。而且你可以下一个在手机上，真是走到哪用到哪啊。不是有很多人说，非硬件级的方案不用么？手机，这是最好的硬件方案了。:) 还有很重要的，如果因为种种原因，你要用一个公用/别人的电脑，就会对配置 1Password + Dropbox 感觉不爽，毕竟有你重要/隐私的数据在里面，同步下来总不太好。算 sha1 的小软件就无所谓了，随便下一个、随便算一下，然后叉掉就行了（要找一个熟悉的，确保不会保存历史记录）。 &#160; 当然，算法只是一方面，为了方便起见，我们不希望每次都算一遍。所以，可以配合浏览器原生的记住密码、自动填写、自动同步的功能一起使用，我觉得堪称完美了（特别是 Firefox 还可以设置主密码保护已记住的密码）。 我已经使用这个方法一小段时间了，个人感觉良好。唯一的不爽是，有些 SB 网站居然对密码长度有限制，要求不超过 16/20/25/&#8230; 位。遇到这种情况，只能一边骂 SB [...]]]></description>
			<content:encoded><![CDATA[<p>应推友要求，介绍下我现在是怎么管理密码的 :) 。</p>
<p>这个方法不是我首创，我也是受别人启发，但可以简单论述下为什么这个方法好~。</p>
<p>&nbsp;</p>
<p>这个问题的背景，是这个国家的互联网行业，开发者素养差、管理者道德低的普遍现状（当然，国外也有很多不负责任/不懂如何负责任的网站）。我们对于所有网络服务，普遍处于不信任的状态（特别是国内还多了官僚监管这一层），但是有的时候又不得不用。那么，作为用户，我们如何保护自己的信息安全（这里只谈密码）？</p>
<p>&nbsp;</p>
<p>理想状况：</p>
<ol>
<li>每个网站都使用不同的密码；</li>
<li>而且都很复杂。</li>
</ol>
<p>2 保证了如果某个网站技术不太行，保护措施做得不够好，你的密码也不会轻易被破解；而 1 保证了即使在极端情况下，也只会被泄露这一个网站的密码，不影响你在其它网站上的账户。</p>
<p>&nbsp;</p>
<p>然而，要用人脑来记忆不同网站的不同的复杂的密码，显然是不可行的。所以我们要借助一些辅助措施。有一类软件提供这样的功能，需要的时候，它可以帮你生成一个随机的很复杂的密码，同时把它存起来。你可以注明这是什么网站的密码，然后用一个主密码把这些随机密码都加密起来。所以，软件负责记住不同网站不同的复杂密码，而我们人脑只需要记住一个主密码。</p>
<p>&nbsp;</p>
<p>这是个好主意，但是还不够好。问题在于那些不同网站的密码都是随机生成的，这也就注定了我们的焦虑（我们失去了把控，只能完全依赖于一个黑盒）。我们总会担心记录弄丢了、损坏了、出门在外忘带了（同步？没网络呢、别人的机器呢？），或者某种平台这个软件不支持等等。总之，我们被 lock-in 了！</p>
<p>&nbsp;</p>
<p>我现在的方法是，不使用随机密码，而是用主密码+网站名，然后算 sha1。即：</p>
<blockquote><p>$ sha1sum</p>
<p>password+csdn</p>
<p>^D</p></blockquote>
<p>对，出来一串“乱码”，就用这串乱码做密码。这样做的好处，只要密码后面的网站名不同，生成的“乱码”就完全不同，即使有几个网站同时不靠谱、同时把你的密码（即刚刚生成的“乱码”）泄露了，你的主密码是绝对安全的（当然，要搞复杂一点）。另一方面，你知道这些“乱码”是怎么生成的，所以你不再依赖于某一个单一的软件，因为 sha1 算法是整个计算机系统的重要基础设施之一，哪里都有它的踪影、久经考验。</p>
<p>&nbsp;</p>
<p>哦，你会说，这是程序员的玩意儿，非程序员怎么办？非也，算 sha1 的小软件，可是比密码管理软件分布广泛多了。Windows/Linux/Mac OS、手机、平板⋯哪个平台上没有？不但有，而且很简单、很好用，绿色环保！就算没有，照着公开的算法写一个也不是什么难事。</p>
<p>所以，我们与其小心翼翼地备一个密码管理系统，不如大大方方地随便哪放一个算 sha1 的小软件。而且你可以下一个在手机上，真是走到哪用到哪啊。不是有很多人说，非硬件级的方案不用么？手机，这是最好的硬件方案了。:)</p>
<p>还有很重要的，如果因为种种原因，你要用一个公用/别人的电脑，就会对配置 1Password + Dropbox 感觉不爽，毕竟有你重要/隐私的数据在里面，同步下来总不太好。算 sha1 的小软件就无所谓了，随便下一个、随便算一下，然后叉掉就行了（要找一个熟悉的，确保不会保存历史记录）。</p>
<p>&nbsp;</p>
<p>当然，算法只是一方面，为了方便起见，我们不希望每次都算一遍。所以，可以配合浏览器原生的记住密码、自动填写、自动同步的功能一起使用，我觉得堪称完美了（特别是 Firefox 还可以设置主密码保护已记住的密码）。</p>
<p>我已经使用这个方法一小段时间了，个人感觉良好。唯一的不爽是，有些 SB 网站居然对密码长度有限制，要求不超过 16/20/25/&#8230; 位。遇到这种情况，只能一边骂 SB 的同时，一边截短。。。</p>
<p>&nbsp;</p>
<p>关于 1Password：</p>
<p>1Password 做得太优雅了（只用过 Mac 版），以致于我很乐意帮它做个广告（虽然我没再用它了⋯）。1Password 几个很好的功能：</p>
<ul>
<li><del>自动生成随机复杂密码</del>：跟上面主要的思路相冲突，这功能等于没用；</li>
<li><del>自动记忆、自动填写</del>：浏览器原生支持，相比之下没有优势，等于没用；</li>
<li><del>密码整理/管理非常方便</del>：这是它比浏览器原生的功能强很多的地方。但是密码之所以需要整理，是因为每一个都很独特、都很重要，我们需要搞得它井井有条。但是当我们用了上面 sha1 的算法之后，会突然觉得没必要整理了。我们让浏览器记住，只是为了它能帮我们自动填写，方便一点而已。实际上，那些密码存在数据库里到底是什么鬼样子，我们一点都不担心，反正需要的时候再算一遍好咯。所以，不是 1Password 做得不够好，而是这功能对我已不再重要。</li>
</ul>
<p>呵呵，好像说得它一点用处没有的样子，其实我们也可以用 1Password 记上面 sha1 产生的密码，它的好处比如：</p>
<ul>
<li>虽然密码整理已不再重要，但是它毕竟满好用的，说不定我们什么时候想整理整理呢？</li>
<li>1Password 是跨浏览器的。如果用浏览器原生的记忆密码的功能，并且 Firefox、Chrome 同时用的话，同一个网站的 sha1 可能需要算两遍呵呵。而 1Password 是跨浏览器的，算一次就可以。</li>
<li>除了网站的密码，1Password 还可以用来记信用卡都资料。</li>
</ul>
<p>另外，如果不太喜欢上面说的所谓的算 sha1 那么 geek 的做法，也是用 1Password 的一个很好的理由，它是非常用户友好的。与 1Password 类似的，可以用开源且恰好免费（好吧，我是想给你一个印象：开源不一定免费）的 KeePass。</p>
<p>（完）</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2011/12/%e6%88%91%e6%98%af%e6%80%8e%e4%b9%88%e7%ae%a1%e7%90%86%e5%af%86%e7%a0%81%e7%9a%84/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>怎样保护用户密码才靠谱</title>
		<link>http://wangcongming.info/2011/12/%e6%80%8e%e6%a0%b7%e4%bf%9d%e6%8a%a4%e7%94%a8%e6%88%b7%e5%af%86%e7%a0%81%e6%89%8d%e9%9d%a0%e8%b0%b1/</link>
		<comments>http://wangcongming.info/2011/12/%e6%80%8e%e6%a0%b7%e4%bf%9d%e6%8a%a4%e7%94%a8%e6%88%b7%e5%af%86%e7%a0%81%e6%89%8d%e9%9d%a0%e8%b0%b1/#comments</comments>
		<pubDate>Wed, 21 Dec 2011 18:41:07 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[密码]]></category>

		<guid isPermaLink="false">http://wangcongming.info/?p=1141</guid>
		<description><![CDATA[CSDN 密码泄露，把我的也给泄掉了⋯⋯好几年没用了，躺着也中枪啊。幸好只是一个低级别的密码。忙着改密码的同时，也在考虑要不要启用 sha1(master password + domain name) 的密码方案。。。   好吧，还是说点有趣的，怎样保护用户密码才靠谱？ 1、数据库存储 原始： save2db(username, password) 进化： save2db(username, md5(password)) 再进化： random salt = GUID save2db(username, salt, md5(password.salt)) 靠谱方案： const globalSalt = [a-z]+[A-Z]+[0-9]+[%$#@!~*...]+ random privateSalt = GUID save2db(username, privateSalt, sha1(globalSalt.password.privateSalt)) 可接受的简化方案： save2db(username, sha1(domain.password.username)   为什么要搞个 globalSalt？ globalSalt 写在代码中，也就是说，万一你的数据库泄露了（代码还没泄露），仍然有一道安全防线在保护你的用户。只有一个 salt 的情况下，虽然使得字典攻击变得更难，但如果用户密码不够长、不够复杂，暴力攻击仍是很轻松的事（因为既然你的数据库已经泄露了，用户的 salt 自然也就露掉了）。而有了 globalSalt，只要代码仍然安全（攻击者不知道你 globalSalt 的值为多少的情况下），它就能保证跟用户的密码组合起来变得非常长、非常复杂，超出了暴力破解的实际可能。   可不可以只用一个 globalSalt？ [...]]]></description>
			<content:encoded><![CDATA[<p>CSDN 密码泄露，把我的也给泄掉了⋯⋯好几年没用了，躺着也中枪啊。幸好只是一个低级别的密码。忙着改密码的同时，也在考虑要不要启用 sha1(master password + domain name) 的密码方案。。。</p>
<p> </p>
<p>好吧，还是说点有趣的，怎样保护用户密码才靠谱？</p>
<p><strong>1、数据库存储</strong></p>
<p><strong>原始：</strong></p>
<blockquote><p>save2db(username, password)</p>
</blockquote>
<p>
<strong>进化：</strong></p>
<blockquote><p>save2db(username, md5(password))</p>
</blockquote>
<p>
<strong>再进化：</strong></p>
<blockquote><p>random salt = GUID</p>
<p>save2db(username, salt, md5(password.salt))</p>
</blockquote>
<p>
<strong>靠谱方案：</strong></p>
<blockquote><p>const globalSalt = [a-z]+[A-Z]+[0-9]+[%$#@!~*...]+</p>
<p>random privateSalt = GUID</p>
<p>save2db(username, privateSalt, sha1(globalSalt.password.privateSalt))</p>
</blockquote>
<p>
<strong>可接受的简化方案：</strong></p>
<blockquote><p>save2db(username, sha1(domain.password.username)</p>
</blockquote>
<p>
 </p>
<p><strong>为什么要搞个 globalSalt？</strong></p>
<p>globalSalt 写在代码中，也就是说，万一你的数据库泄露了（代码还没泄露），仍然有一道安全防线在保护你的用户。只有一个 salt 的情况下，虽然使得字典攻击变得更难，但如果用户密码不够长、不够复杂，暴力攻击仍是很轻松的事（因为既然你的数据库已经泄露了，用户的 salt 自然也就露掉了）。而有了 globalSalt，只要代码仍然安全（攻击者不知道你 globalSalt 的值为多少的情况下），它就能保证跟用户的密码组合起来变得非常长、非常复杂，超出了暴力破解的实际可能。</p>
<p> </p>
<p><strong>可不可以只用一个 globalSalt？</strong></p>
<p>不可以。否则，好事者就可能在知道你 globalSalt 的情况为你这个网站专门生成一个字典，一次性搞定所有用户。privateSalt 的存在，使各个用户的 salt 都不一样，因此需要为每个用户生成一个专用的字典，不具备实际可行性。简单地说，globalSalt 防暴力攻击、privateSalt 防字典攻击。</p>
<p> </p>
<p><strong>简化方案中，可不可以不要 domain，只用 username？</strong></p>
<p>不可以。一、有的用户，即使是用户名 + 密码仍然不够长，抗不了暴力；二、我们不仅是要（尽可能）保证 salt 的全站唯一，而是要全球唯一。有些用户名如 admin, root, webmaster 等非常通用，起不到 salt 应有的作用。</p>
<p> </p>
<p><strong>2、修改密码</strong></p>
<ul></ul>
<ul>
<li>改密码，必先验证老密码，而不是登录着就让改。否则，就给 Session Hijacking 变成进一步的灾难修了条大道。</li>
<p>
</ul>
<ul>
<li>如果老密码输错了，启用验证码保护。否则，就是 Session Hijacking 后暴力破解的后门。</li>
<p>
</ul>
<ul>
<li>清 session，使所有登录的（如果支持一个帐号同时多处登录）cookie 失效。改了密码，就应该要求该用户所有会话重新验证。因为用户密码已经改了，表示原密码不再是有效的，甚至可能已经泄露了。</li>
<p>
</ul>
<p> </p>
<p><strong>3、其它</strong></p>
<ul></ul>
<ul>
<li>传输密码时用 HTTPS；</li>
<p>
</ul>
<ul>
<li>最好全程 HTTPS，杜绝 Session Hijacking（WIFI 什么的，最容易中招了）；</li>
<p>
</ul>
<ul>
<li>避免 Session Fixation（永远重新生成，不通过 URL 传输 SID）；</li>
<p>
</ul>
<ul>
<li>除特别需要，httpd 进程对代码目录只应该有读权限，而不应有写权限。你懂的，后门啊什么的最讨厌了~；</li>
<p>
</ul>
<ul>
<li>定期 $ git status（.git 目录为 root 专属），如果不是 working directory clean，那就该报警了喂！</li>
<p>
</ul>
<ul>
<li>Injection、XSS 什么的，呃⋯超纲了，打住~。</li>
<p>
</ul>
<p> </p>
<p>虽然都是很简单的事，但如果一条条验证，估计国内绝大部分网站都能找出问题，包括那些人们觉得很牛逼的（CSDN，程序员的社区啊，“全球最大”啊…存储密码用的是最原始的方法）。关于保护用户信息安全，你还有什么想法？</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2011/12/%e6%80%8e%e6%a0%b7%e4%bf%9d%e6%8a%a4%e7%94%a8%e6%88%b7%e5%af%86%e7%a0%81%e6%89%8d%e9%9d%a0%e8%b0%b1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Git 系列之四：Git 进阶功能</title>
		<link>http://wangcongming.info/2010/07/git-%e7%b3%bb%e5%88%97%e4%b9%8b%e5%9b%9b%ef%bc%9agit-%e8%bf%9b%e9%98%b6%e5%8a%9f%e8%83%bd/</link>
		<comments>http://wangcongming.info/2010/07/git-%e7%b3%bb%e5%88%97%e4%b9%8b%e5%9b%9b%ef%bc%9agit-%e8%bf%9b%e9%98%b6%e5%8a%9f%e8%83%bd/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 07:38:59 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[git]]></category>

		<guid isPermaLink="false">http://wangcongming.info/?p=246</guid>
		<description><![CDATA[【TIP】在我们的《Windows 下 Git 配置与使用指南》 中，有介绍大家使用 $ git go 命令。其实，这并非 Git 的原生命令，它是我们自定义的一个 alias（别名），由 $git add、$git commit、$git push 和 $git pull 四个命令组合而成。待熟悉之后，你可以直接使用这些原生命令，或者自定义更适合自己的 alias。 add 添加新文件到 Git 代码仓库的索引中 $ git add filename mv 移动或重命名文件 $ git mv old-filename new-filename rm 从工作目录和 Git 代码索引中删除文件 $ git rm filename status 查看目前工作目录的代码状态，自上次提交以来的添加、修改和删除等 $ git status diff 查看自上次提交以来，本地代码改动的具体情况 $ git diff commit [...]]]></description>
			<content:encoded><![CDATA[<p>【TIP】在我们的<a href="http://wangcongming.info/2010/07/31/git-%E7%B3%BB%E5%88%97%E4%B9%8B%E4%B8%89%EF%BC%9Awindows-%E4%B8%8B-git-%E9%85%8D%E7%BD%AE%E4%B8%8E%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/">《Windows 下 Git 配置与使用指南》</a> 中，有介绍大家使用 $ git go 命令。其实，这并非 Git 的原生命令，它是我们自定义的一个 alias（别名），由 $git  add、$git commit、$git push 和 $git pull  四个命令组合而成。待熟悉之后，你可以直接使用这些原生命令，或者自定义更适合自己的 alias。</p>
<h2 style="margin-top: 40px; font-weight: bold;">add</h2>
<p>添加新文件到 Git 代码仓库的索引中</p>
<pre>$ git add filename</pre>
<h2 style="margin-top: 40px; font-weight: bold;">mv</h2>
<p>移动或重命名文件</p>
<pre>$ git mv old-filename new-filename</pre>
<h2 style="margin-top: 40px; font-weight: bold;">rm</h2>
<p>从工作目录和 Git 代码索引中删除文件</p>
<pre>$ git rm filename</pre>
<h2 style="margin-top: 40px; font-weight: bold;">status</h2>
<p>查看目前工作目录的代码状态，自上次提交以来的添加、修改和删除等</p>
<pre>$ git status</pre>
<h2 style="margin-top: 40px; font-weight: bold;">diff</h2>
<p>查看自上次提交以来，本地代码改动的具体情况</p>
<pre>$ git diff</pre>
<h2 style="margin-top: 40px; font-weight: bold;">commit</h2>
<p>提交修改的代码（只是提交到本地的代码库，不会推送到服务器）</p>
<pre>$ git commit -am '修改说明'</pre>
<p>如果觉得刚提交的“修改说明”写得不够好，可输入以下命令调整</p>
<pre>$ git commit --amend</pre>
<h2 style="margin-top: 40px; font-weight: bold;">push</h2>
<p>将自上次 push 以来的，本地历次 commit，推送到服务器</p>
<p>结合我们的实际，应该这样写：</p>
<pre>$ git push origin master:your-id</pre>
<p>其中，master 是本地的分支名；your-id 填你在服务器上的 id，服务器的版本库里会有以你的 id 为名称的分支。</p>
<h2 style="margin-top: 40px; font-weight: bold;">pull</h2>
<p>将别人推送到服务器的代码，拉到你的机器里</p>
<pre>$ git pull</pre>
<h2 style="margin-top: 40px; font-weight: bold;">log</h2>
<p>查看修改记录，含作者、时间、修改说明等</p>
<pre>$ git log</pre>
<h2 style="margin-top: 40px; font-weight: bold;">show</h2>
<p>显示具体的代码改动情况</p>
<h3 style="font-weight: normal;">显示最后一次 commit 修改的内容：</h3>
<pre>$ git show</pre>
<h3 style="font-weight: normal;">显示指定 commit 修改的内容：</h3>
<p>【TIP】git log 命令中，每条 commit 会有一长长的字符串，此即 commid id，取其前面五六位即可。</p>
<pre>$ git show commit-id</pre>
<h2 style="margin-top: 40px; font-weight: bold;">branch</h2>
<p>分支管理</p>
<h3 style="font-weight: normal;">列出所有分支（当前所在分支前会有“*”号）：</h3>
<pre>$ git branch</pre>
<h3 style="font-weight: normal;">新建分支：</h3>
<pre>$ git branch 新分支名</pre>
<h3 style="font-weight: normal;">删除分支：</h3>
<pre>$ git branch -d 欲删除的分支名</pre>
<p>【注意！】不要把 &#8216;-d&#8217; 写成了 &#8216;-D&#8217;，危险！</p>
<ul>
<li>-d：要求：被删除分支的所有修改，已经合并到当前分支；</li>
<li>-D：直接删除，未合并的代码，将被丢弃！</li>
</ul>
<h2 style="margin-top: 40px; font-weight: bold;">checkout</h2>
<h3 style="font-weight: normal;">恢复某个已修改的文件（撤销未提交的修改）：</h3>
<pre>$ git checkout file-name</pre>
<h3 style="font-weight: normal;">切换到另外的分支，进行开发：</h3>
<pre>$ git checkout branch-name</pre>
<p>【注意！】该命令可能伴随大量的文件增删/修改。Windows 下，改动已被占用的文件可能会被拒绝，导致版本库出现严重问题。如果确实要这样做，安全起见，最好先注销一次。</p>
<h2 style="margin-top: 40px; font-weight: bold;">merge</h2>
<p>合并指定分支到当前分支：</p>
<pre>$ git merge branch-name</pre>
<h2 style="margin-top: 40px; font-weight: bold;">revert</h2>
<p>还原已提交的修改（已经提交过的修改，可以反悔～）</p>
<h3 style="font-weight: normal;">还原最近一次提交的修改：</h3>
<pre>$ git revert HEAD</pre>
<h3 style="font-weight: normal;">还原指定版本的修改：</h3>
<pre>$ git revert commit-id</pre>
<h2 style="margin-top: 40px; font-weight: bold;">stash</h2>
<p>先将未提交的修改暂存起来，接着清除所有改动，使之与没修改时一样。</p>
<p>若你正在开发功能 A，又需立即去开发功能 B。A 的代码正改到一半，未认真整理，你不想立即提交。此时……请呼叫 stash ～。</p>
<h3 style="font-weight: normal;">它会使你所有未提交的修改瞬间不见了：</h3>
<pre>$ git stash</pre>
<h3 style="font-weight: normal;">它会使刚刚不见了的修改，瞬间又回来了：</h3>
<pre>$ git stash pop</pre>
<p style="margin-top: 40px;">【TIP】以上命令皆有更多参数，另有一些 Git 命令我们此处没有介绍。但是，这已足令你使用 Git 时游刃有余，你会觉得，Git 简直是一件神器！:-)</p>
<p>【TIP】&#8217;$ git help&#8217; 与 &#8216;$ git help 命令名&#8217; 会在你需要的时候，无私地帮助你。:-)</p>
<h2 style="margin-top: 40px; font-weight: bold;">附：git push 失败的解决办法</h2>
<p>假设执行操作：</p>
<pre>1. 修改代码
2. git commit
3. git push</pre>
<p>此时 push 失败（错误提示：! [rejected]        master -&gt; master (non-fast-forward) ）</p>
<p>解决办法：</p>
<pre>$ git pull</pre>
<p>若成功，则：</p>
<pre>$ git push origin master:your-id</pre>
<p>完事。</p>
<p>若失败（提示：CONFLICT (content): Merge conflict in 文件名），则：</p>
<p>冲突的文件会有类似下面的代码块：</p>
<pre>&lt;&lt;&lt;&lt;HEAD
你修改的代码
============
其他人修改的代码
&gt;&gt;&gt;&gt;&gt;commit id of others'</pre>
<p>考虑你和他人对代码的修改，更新成合适的内容，并删除 &lt;&lt;&lt;、===、&gt;&gt;&gt; 3行标记符号，保存文件。</p>
<pre>$ git commit -am "resolve conflict"
$ git push origin master:your-id</pre>
<p>更详细的说明，可以阅读 $git push &#8211;help 该文档的 NOTE ABOUT FAST-FORWARDS 一节。</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2010/07/git-%e7%b3%bb%e5%88%97%e4%b9%8b%e5%9b%9b%ef%bc%9agit-%e8%bf%9b%e9%98%b6%e5%8a%9f%e8%83%bd/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Git 系列之三：Windows 下 Git 配置与使用指南</title>
		<link>http://wangcongming.info/2010/07/git-%e7%b3%bb%e5%88%97%e4%b9%8b%e4%b8%89%ef%bc%9awindows-%e4%b8%8b-git-%e9%85%8d%e7%bd%ae%e4%b8%8e%e4%bd%bf%e7%94%a8%e6%8c%87%e5%8d%97/</link>
		<comments>http://wangcongming.info/2010/07/git-%e7%b3%bb%e5%88%97%e4%b9%8b%e4%b8%89%ef%bc%9awindows-%e4%b8%8b-git-%e9%85%8d%e7%bd%ae%e4%b8%8e%e4%bd%bf%e7%94%a8%e6%8c%87%e5%8d%97/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 07:35:06 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[msysGit]]></category>
		<category><![CDATA[密钥]]></category>

		<guid isPermaLink="false">http://wangcongming.info/?p=237</guid>
		<description><![CDATA[一、安装 默认安装：msysGit 二、配置 1、C:\Program Files\Git\etc\gitconfig 添加： 【注意！】请将第二行最后的 “your-id” 修改成你在服务器上的实际 id，默认是姓名拼音。 [alias] go = "! bash -c \"git pull &#38;&#38; git add .; if [ \\\"$*\\\" == \\\"\\\" ]; then git commit -a; else git commit -am \\\"$*\\\"; fi; git push origin master:your-id;\"" [core] autocrlf = false [gui] encoding = utf-8 [i18n] commitencoding = GB2312 [user] [...]]]></description>
			<content:encoded><![CDATA[<h2 style="margin-top: 30px; font-weight: bold;">一、安装</h2>
<p>默认安装：<a href="http://code.google.com/p/msysgit/downloads/detail?name=Git-1.7.0.2-preview20100309.exe">msysGit</a></p>
<h2 style="margin-top: 40px; font-weight: bold;">二、配置</h2>
<p>1、C:\Program Files\Git\etc\gitconfig 添加：<br />
<strong>【注意！】请将第二行最后的 “your-id” 修改成你在服务器上的实际 id，默认是姓名拼音。</strong></p>
<pre>[alias]
    go = "! bash -c \"git pull &amp;&amp; git add .; if [ \\\"$*\\\" == \\\"\\\" ]; then git commit -a; else git commit -am \\\"$*\\\"; fi; git push origin master:your-id;\""
[core]
    autocrlf = false
[gui]
    encoding = utf-8
[i18n]
    commitencoding = GB2312
[user]
    email = xxx@gmail.com
    name = 某某某</pre>
<p>2、C:\Program Files\Git\etc\inputrc 修改两行为：</p>
<pre>set output-meta on
set convert-meta off</pre>
<p>3、C:\Program Files\Git\etc\git-completion.bash 末尾增加：</p>
<pre>alias ls='ls --show-control-chars --color=auto'</pre>
<p>4、C:\Program Files\Git\etc\profile 末尾增加：</p>
<pre>export LESSCHARSET=utf-8</pre>
<p>【TIP】以上文件最好使用支持 unix 格式的编辑器修改（如 Notepad++、NetBeans），最次也用“写字板”而非“记事本”。</p>
<p>【TIP】若想了解为什么这样设置，请参见：<a href="http://wangcongming.info/2010/07/31/windows-%E4%B8%8B-git-%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84%E9%80%89%E6%8B%A9%EF%BC%8C%E5%8F%8A-msysgit-%E5%90%84%E7%A7%8D%E4%B8%AD%E6%96%87%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%E5%86%B3/">Windows 下 Git 客户端的选择，及 msysGit 各种中文问题的解决</a></p>
<h2 style="margin-top: 40px; font-weight: bold;">三、生成密钥</h2>
<p>安装完后，需要生成一对 Key（这里指密钥），然后才能通过加密的方式和服务器的代码库取得同步。</p>
<p>到开始菜单，找到“Git Bash”，运行之，并执行以下命令：</p>
<pre>$ ssh-keygen -t rsa</pre>
<p>程序会提示您输入密钥的文件名，直接按回车即可。<br />
然后会要求你输入一个密码，将来在使用密钥的时候需要提供这个密码。可以输入，也可以不输入直接回车（无论输入还是不输入，都会要求你确认一次）。<br />
确认完毕后，程序将生成一对密钥存放在以下文件夹：</p>
<pre>C:\Users\Administrator[这里替换成你的用户名]\.ssh</pre>
<p>密钥分成两个文件，一个私钥（id_rsa）、一个公钥（id_rsa.pub）。<br />
私钥保存在您的电脑上，公钥交项目负责人添加到服务器上。用户必须拥有与服务器公钥所配对的私钥，才能访问服务器上的代码库。</p>
<p><strong>【注意！】为了项目代码的安全，请妥善保管你的私钥！因为一旦私钥外泄，将可能导致服务器上的代码被泄漏！</strong></p>
<h2 style="margin-top: 40px; font-weight: bold;">四、使用</h2>
<h3>1、克隆代码库</h3>
<p>使用 Windows 资源管理器，打开你打算存放项目代码的文件夹，点右键选择 Git Bash。</p>
<p>在我们的项目管理系统中，每个项目的首页，都有写明代码克隆的地址，比如我们用于测试目的的沙盒项目：</p>
<pre>$ git clone your-name@testing.aysaas.com:/var/projects/sandbox</pre>
<p>在 Git Bash 中运行这条命令就能将沙盒项目中的所有代码（其实只是几个随便测试的文件）克隆到本地。</p>
<p>接着您就可以打开习惯的 IDE（如 NetBeans），投入到项目的开发中啦～！</p>
<p>【TIP】上面命令中的 your-name 要改成你在服务器上实际的用户名。</p>
<h3>2、查看修改差异</h3>
<p>开发过程中，如果你想了解修改了哪些代码，总览所有代码的改动情况，可以在 Git Bash 中输入此命令：</p>
<pre>$ git diff</pre>
<p>【TIP】Git Bash diff 的时候有两个缺点：一、窗口太窄，可能显示不下整行的代码；二、如果代码中有中文，会乱码。如果你碰到这两个问题，可以在项目文件夹下点右键，选择 Git Gui。</p>
<h3>3、提交修改</h3>
<p>每当完成一个阶段的代码，就需要提交代码以记录进展，方便日后查找问题以及团队协作。</p>
<pre>$ git go aaa 修改说明（改动了什么？为什么这样改？）</pre>
<p>【TIP】别忘了 go 后面的 aaa，关于 &#8216;git go&#8217; 命令的详细说明，请参见 <a href="http://wangcongming.info/2010/07/31/windows-%E4%B8%8B-git-%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84%E9%80%89%E6%8B%A9%EF%BC%8C%E5%8F%8A-msysgit-%E5%90%84%E7%A7%8D%E4%B8%AD%E6%96%87%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%E5%86%B3/">Windows 下 Git 客户端的选择，及 msysGit 各种中文问题的解决</a></p>
<p><strong>【TIP】请尽量养成勤提交的好习惯。当代码不幸出现问题时，比较容易找出从什么时刻开始出现问题，并回退到该时刻进行调试，最大限度保护已完成的阶段性工作。</strong></p>
<p>【TIP】以上命令，都需要在项目目录下运行。Git Bash 在命令提示符前，会显示当前所在的目录。如果当前不在项目目录之下，需要用 cd 命令切换到项目所在目录。<br />
简单的办法，就是先在资源管理器里打开项目文件夹，再点右键，选择 Git Bash。</p>
<h2 style="margin-top: 40px; font-weight: bold;">五、总结</h2>
<p>至此，从获取代码、查看差异、到提交代码，整个流程都熟悉了。Git 还有比较高级的技巧，大家可以参考 <a href="http://wangcongming.info/2010/07/31/git-%E7%B3%BB%E5%88%97%E4%B9%8B%E5%9B%9B%EF%BC%9Agit-%E8%BF%9B%E9%98%B6%E5%8A%9F%E8%83%BD/">Git 进阶功能</a> 或在线找进一步的资料学习。</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2010/07/git-%e7%b3%bb%e5%88%97%e4%b9%8b%e4%b8%89%ef%bc%9awindows-%e4%b8%8b-git-%e9%85%8d%e7%bd%ae%e4%b8%8e%e4%bd%bf%e7%94%a8%e6%8c%87%e5%8d%97/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Git 系列之二：Windows 下 Git 客户端的选择，及 msysGit 各种中文问题的解决</title>
		<link>http://wangcongming.info/2010/07/windows-%e4%b8%8b-git-%e5%ae%a2%e6%88%b7%e7%ab%af%e7%9a%84%e9%80%89%e6%8b%a9%ef%bc%8c%e5%8f%8a-msysgit-%e5%90%84%e7%a7%8d%e4%b8%ad%e6%96%87%e9%97%ae%e9%a2%98%e7%9a%84%e8%a7%a3%e5%86%b3/</link>
		<comments>http://wangcongming.info/2010/07/windows-%e4%b8%8b-git-%e5%ae%a2%e6%88%b7%e7%ab%af%e7%9a%84%e9%80%89%e6%8b%a9%ef%bc%8c%e5%8f%8a-msysgit-%e5%90%84%e7%a7%8d%e4%b8%ad%e6%96%87%e9%97%ae%e9%a2%98%e7%9a%84%e8%a7%a3%e5%86%b3/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 07:31:07 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[GB2312]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[msysGit]]></category>
		<category><![CDATA[NBGit]]></category>
		<category><![CDATA[NetBeans]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[TortoiseGit]]></category>
		<category><![CDATA[utf-8]]></category>
		<category><![CDATA[中文]]></category>
		<category><![CDATA[乱码]]></category>

		<guid isPermaLink="false">http://wangcongming.info/?p=230</guid>
		<description><![CDATA[在 Windows 下用 NetBeans 做 PHP 开发，首先想到的是 NetBeans 的插件：NBGit。 评价：能用；若需没有的功能，可以自定义菜单调用自定义 bat 脚本；开发不活跃，使用没有信心。 第二个则是：TortoiseGit，SVN 小乌龟的 Git 版本。 评价：该有的功能基本都有了，还是不错的。 另外，TortoiseGit 只是 GUI 工具，使用它需要先安装 msysGit，这是正宗的 Git 之 Windows 版本。msysGit 有个简单的 GUI 工具，及简单的 Explorer 集成；但它自带的 Bash 非常好用，深得 Linux 的真传。 选择：msysGit。 理由： NBGit 不用说，功能都不完善，还需要自己定制 bat 脚本（若此，则它同样要依赖 msysGit）；开发不活跃，很可能 NetBeans 下个版本更新就不能用了；况且，我们还有别的项目，不使用 NetBeans。 TortoiseGit 从功能上说是完善的，但它只是功能的堆砌而已，使用时完全体会不到 GUI 带来的便利。相反，它让人感觉很繁琐，一个劲地点鼠标，点来点去全是跟菜单打交道，远离了 Git 命令、远离了 Git 输出提示、远离了真相。 msysGit 的 [...]]]></description>
			<content:encoded><![CDATA[<p>在 Windows 下用 NetBeans 做 PHP 开发，首先想到的是 NetBeans 的插件：NBGit。<br />
评价：能用；若需没有的功能，可以自定义菜单调用自定义 bat 脚本；开发不活跃，使用没有信心。</p>
<p>第二个则是：TortoiseGit，SVN 小乌龟的 Git 版本。<br />
评价：该有的功能基本都有了，还是不错的。</p>
<p>另外，TortoiseGit 只是 GUI 工具，使用它需要先安装 msysGit，这是正宗的 Git 之 Windows 版本。msysGit 有个简单的 GUI 工具，及简单的 Explorer 集成；但它自带的 Bash 非常好用，深得 Linux 的真传。</p>
<p><strong>选择：msysGit。</strong><br />
理由：<br />
NBGit 不用说，功能都不完善，还需要自己定制 bat 脚本（若此，则它同样要依赖 msysGit）；开发不活跃，很可能 NetBeans 下个版本更新就不能用了；况且，我们还有别的项目，不使用 NetBeans。</p>
<p>TortoiseGit 从功能上说是完善的，但它只是功能的堆砌而已，使用时完全体会不到 GUI 带来的便利。相反，它让人感觉很繁琐，一个劲地点鼠标，点来点去全是跟菜单打交道，远离了 Git 命令、远离了 Git 输出提示、远离了真相。</p>
<p>msysGit 的 Bash 非常好用；加上 Git 强大的 alias 功能，我们完全可以自定义一个 $ git go，使得 90% 的情况下只需要这一个命令，即使是不熟悉命令行的 Windows 用户也会觉得很好玩；因为 NBGit、TortoiseGit 都需要 msysGit 做底层，我们直接用底层工具也避免了上层 GUI 带来的额外的 bug。</p>
<p>需要的配置：</p>
<p><strong>1、</strong>C:\Program Files\Git\etc\git-completion.bash：</p>
<pre><strong>alias ls='ls --show-control-chars --color=auto'</strong></pre>
<p>说明：使得在 Git Bash 中输入 ls 命令，可以正常显示中文<strong>文件名</strong>。</p>
<p><strong>2、</strong>C:\Program Files\Git\etc\inputrc：</p>
<pre><strong>set output-meta on
set convert-meta off</strong></pre>
<p>说明：使得在 Git Bash 中可以正常<strong>输入</strong>中文，比如中文的 commit log。</p>
<p><strong>3、</strong>C:\Program Files\Git\etc\profile：</p>
<pre><strong>export LESSCHARSET=utf-8</strong></pre>
<p>说明：$ git log 命令不像其它 vcs 一样，n 条 log 从头滚到底，它会恰当地停在第一页，按 space 键再往后翻页。这是通过将 log 送给 less 处理实现的。以上即是设置 less 的字符编码，使得 $ git log 可以正常显示中文。其实，它的值不一定要设置为 utf-8，比如 latin1 也可以……。还有个办法是 $ git &#8211;no-pager log，在选项里禁止分页，则无需设置上面的选项。</p>
<p><strong>4、</strong>C:\Program Files\Git\etc\gitconfig：<br />
<strong>[alias]<br />
go =</strong> “! bash -c \”git pull &amp;&amp; git add .; if [ \\\"$*\\\" == \\\"\\\" ]; then git commit -a; else git commit -am \\\”$*\\\”; fi; git push origin master:your-id;\”"</p>
<p>说明：强大的 alias，有了这个，我们 90% 的情况下只需要输入 $ git go 这一个命令，免去了先拉后提交再推的繁琐步骤。</p>
<p>两种用法：<br />
$ git go<br />
或<br />
$ git go aaa 修订说明</p>
<p>命令后带修订说明时，会直接提交。需要注意的是，在“修订说明”之前，有还个“aaa”，这是个 bug，参数中的第一个会被忽略，所以随便写一个凑数的……。</p>
<p>若命令行里没有提供修订说明，则会自动弹出一个编辑器，等待输入。默认的编辑器是 Vim。Vim 的使用是很简单的，首先要明白它有两个模式，一个是命令模式、一个是输入模式。Vim 启动的时候默认的是命令模式，需要先按&#8217;i'键，进入输入模式；然后就正常编辑；编辑完成之后，将输入法切换回英文状态，按 Esc 重新进入命令模式；此时按 &#8216;<strong>(Shift):wq</strong>&#8216; 并回车，w 表示写入保存、q 表示退出。完毕！</p>
<p>若实在不习惯 Vim，也可以设置为其它编辑器：</p>
<pre class="terminal">$ git config --global core.editor "notepad"</pre>
<p>其中 notepad 可以替换为更好用的 wordpad、notepad++ 等（不过它们在命令行里无法直接访问，得先设置 PATH 变量）。</p>
<p>以上 alias 是为 Windows 定制的，Linux 下可以写得更优雅，不过鉴于使用上没分别，就保持一致吧～。</p>
<p><strong></strong><strong>[gui]<br />
encoding = utf-8</strong></p>
<p>说明：我们的代码库是统一用的 utf-8，这样设置可以在 git gui 中正常显示代码中的中文。</p>
<p><strong>[i18n]<br />
commitencoding = GB2312</strong></p>
<p>说明：如果没有这一条，虽然我们在本地用 $ git log 看自己的中文修订没问题，但，一、我们的 log 推到服务器后会变成乱码；二、别人在 Linux 下推的中文 log 我们 pull 过来之后看起来也是乱码。这是因为，我们的 commit log 会被先存放在项目的 .git/COMMIT_EDITMSG 文件中；在中文 Windows 里，新建文件用的是 GB2312 的编码；但是 Git 不知道，当成默认的 utf-8 的送出去了，所以就乱码了。有了这条之后，Git 会先将其转换成 utf-8，再发出去，于是就没问题了。</p>
<p><strong>以上，给 Windows 下的同事在 Git Bash 里推代码就比较完美了。不过仍然有 3 个问题：</strong></p>
<p>1、上面的 alias $ git go 有 bug，代码修订说明之前要输入一串字符凑数；</p>
<p>2、$ git diff，如果代码里有中文，会显示乱码；</p>
<p>3、$ git checkout 有时候需要修改/增删很多文件，如果某些文件被占用，会被 Windows 拒绝，导致失败，甚至可能造成版本库出现无法修复的问题。</p>
<p>这 3 个都是可承受的问题，前两个应该有办法解决；第 3 个归功于文件系统，只能尽量避免 checkout，实在需要的时候先注销一次，就不会有问题了。</p>
<p><strong>【TIP】</strong>该文只是解释说明，具体操作请按<a href="http://wangcongming.info/2010/07/31/git-%E7%B3%BB%E5%88%97%E4%B9%8B%E4%B8%89%EF%BC%9Awindows-%E4%B8%8B-git-%E9%85%8D%E7%BD%AE%E4%B8%8E%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/">《Windows 下 git 配置与使用指南》Wiki</a> 执行。</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2010/07/windows-%e4%b8%8b-git-%e5%ae%a2%e6%88%b7%e7%ab%af%e7%9a%84%e9%80%89%e6%8b%a9%ef%bc%8c%e5%8f%8a-msysgit-%e5%90%84%e7%a7%8d%e4%b8%ad%e6%96%87%e9%97%ae%e9%a2%98%e7%9a%84%e8%a7%a3%e5%86%b3/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Git 系列之一：版本控制的概念、分布式、Git 简介及其工作流程</title>
		<link>http://wangcongming.info/2010/07/%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6%e7%9a%84%e6%a6%82%e5%bf%b5%e3%80%81%e5%88%86%e5%b8%83%e5%bc%8f%e3%80%81git-%e7%ae%80%e4%bb%8b%e5%8f%8a%e5%85%b6%e5%b7%a5%e4%bd%9c%e6%b5%81%e7%a8%8b/</link>
		<comments>http://wangcongming.info/2010/07/%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6%e7%9a%84%e6%a6%82%e5%bf%b5%e3%80%81%e5%88%86%e5%b8%83%e5%bc%8f%e3%80%81git-%e7%ae%80%e4%bb%8b%e5%8f%8a%e5%85%b6%e5%b7%a5%e4%bd%9c%e6%b5%81%e7%a8%8b/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 07:24:06 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[git]]></category>

		<guid isPermaLink="false">http://wangcongming.info/?p=207</guid>
		<description><![CDATA[UPDATE：这里记录的“Git 工作流程”比较适合于团队大部分人没有使用过 Git 的情况，能够简单无障碍入门；以及，适合于系统比较大，不同的人工作于不同的部分，彼此进度不一的情况。日志写作时，我们正好符合这两个情况，所以采用了所述的流程。随着时间的推移，团队成员使用 Git 已经比较熟练，而我们系统的开发也逐渐成熟，现已转用了另一种流程。大体而言，跟这个思路比较接近：http://nvie.com/posts/a-successful-git-branching-model/ 。 —— 注： Git 的强大、灵活、好用，毋庸置疑。 但也正是 Git 的灵活性，在公司推行时，如何执行统一的流程成为一个问题。我想了不少时间才制订出一个办法。 目的是规范、统一。还有就是，Windows 下的同事，特别是不熟悉命令行的同事，怎样才能使他们好理解，并且觉得简单（之前大家觉得概念太多，难以理解；步骤多，记不住，不小心就搞错，冲突频发）。 说到 Windows，Git 在 Windows 下不如 Linux 下好使，这也是一个需要考虑的问题。 同样是在公司 Wiki 上写的，再次拿到 Blog 来凑数呵呵～。 版本控制 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 简单地说，就是将在本地开发的代码，定时推送到服务器。每一次修改，记录下它的作者、时间及修改说明等。 相对的，我们也可以从服务器下拉其他人推送的代码，并了解它的作者、时间、修改说明及其具体的修改内容。 这样，版本控制给团队协作开发提供了极大的方便。即使是一个人开发，因为它记录下了我们整个的开发历史，也是极有帮助和价值的。 比如，如果某次修改甚至整个系统出现问题，它也能帮助找回我们珍贵的代码。 分布式版本控制 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; 更进一步，分布式版本控制工具使得我们在本机上即拥有完整的功能，不依赖于服务器，使用更为方便。它们往往也提供其它更好用或更强大的功能，比如灵活的分支管理。 Git &#8212;&#8212;&#8211; Git 是 Linux 之父 Linus Trovalds，为管理 Linux 内核代码而建立的，被认为是分布式版本控制工具中的顶级水准。智能、友好、强健、高效。 Git 工作流程 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 1、使用中央服务器辅助协作； 2、每人在服务器拥有一个以自己 id 为名称的分支； 3、各人只许推送更新到自己的分支，不允许推送到别人的分支或者 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>UPDATE：</strong>这里记录的“Git 工作流程”比较适合于团队大部分人没有使用过 Git 的情况，能够简单无障碍入门；以及，适合于系统比较大，不同的人工作于不同的部分，彼此进度不一的情况。日志写作时，我们正好符合这两个情况，所以采用了所述的流程。随着时间的推移，团队成员使用 Git 已经比较熟练，而我们系统的开发也逐渐成熟，现已转用了另一种流程。大体而言，跟这个思路比较接近：http://nvie.com/posts/a-successful-git-branching-model/ 。</p>
<p>——</p>
<p>注：</p>
<p>Git 的强大、灵活、好用，毋庸置疑。</p>
<p>但也正是 Git 的灵活性，在公司推行时，如何执行统一的流程成为一个问题。我想了不少时间才制订出一个办法。</p>
<p>目的是规范、统一。还有就是，Windows 下的同事，特别是不熟悉命令行的同事，怎样才能使他们好理解，并且觉得简单（之前大家觉得概念太多，难以理解；步骤多，记不住，不小心就搞错，冲突频发）。</p>
<p>说到 Windows，Git 在 Windows 下不如 Linux 下好使，这也是一个需要考虑的问题。</p>
<p>同样是在公司 Wiki 上写的，再次拿到 Blog 来凑数呵呵～。</p>
<h2 style="margin-top: 40px; font-weight: bold;">版本控制</h2>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
简单地说，就是将在本地开发的代码，定时推送到服务器。每一次修改，记录下它的作者、时间及修改说明等。</p>
<p>相对的，我们也可以从服务器下拉其他人推送的代码，并了解它的作者、时间、修改说明及其具体的修改内容。</p>
<p>这样，版本控制给团队协作开发提供了极大的方便。即使是一个人开发，因为它记录下了我们整个的开发历史，也是极有帮助和价值的。</p>
<p>比如，如果某次修改甚至整个系统出现问题，它也能帮助找回我们珍贵的代码。</p>
<h2 style="margin-top: 40px; font-weight: bold;">分布式版本控制</h2>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
更进一步，分布式版本控制工具使得我们在本机上即拥有完整的功能，不依赖于服务器，使用更为方便。它们往往也提供其它更好用或更强大的功能，比如灵活的分支管理。</p>
<h2 style="margin-top: 40px; font-weight: bold;">Git</h2>
<p>&#8212;&#8212;&#8211;<br />
Git 是 Linux 之父 Linus Trovalds，为管理 Linux 内核代码而建立的，被认为是分布式版本控制工具中的顶级水准。智能、友好、强健、高效。</p>
<h2 style="margin-top: 40px; font-weight: bold;">Git 工作流程</h2>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
1、使用中央服务器辅助协作；</p>
<p>2、每人在服务器拥有一个以自己 id 为名称的分支；</p>
<p>3、各人只许推送更新到自己的分支，不允许推送到别人的分支或者 master；</p>
<p>4、master 由专人管理，在合适时 merge 其它分支（开发初期每日自动 merge 各人分支，生产化后则由人工 merge 经过 review 的分支）；</p>
<p>5、代码修改 merge 到 master 后，将同步到所有终端。</p>
<p>【TIP】：熟悉之后，你可以创建类似 myId_branchName 的其它分支。</p>
<p>【TIP】：以上只是概念介绍，至于具体的操作，请参考：<a href="http://wangcongming.info/2010/07/31/git-%E7%B3%BB%E5%88%97%E4%B9%8B%E4%B8%89%EF%BC%9Awindows-%E4%B8%8B-git-%E9%85%8D%E7%BD%AE%E4%B8%8E%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/">《Windows 下 Git 配置与使用指南》</a>、 <a href="http://wangcongming.info/2010/07/31/git-%E7%B3%BB%E5%88%97%E4%B9%8B%E5%9B%9B%EF%BC%9Agit-%E8%BF%9B%E9%98%B6%E5%8A%9F%E8%83%BD/">《Git 进阶功能》</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2010/07/%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6%e7%9a%84%e6%a6%82%e5%bf%b5%e3%80%81%e5%88%86%e5%b8%83%e5%bc%8f%e3%80%81git-%e7%ae%80%e4%bb%8b%e5%8f%8a%e5%85%b6%e5%b7%a5%e4%bd%9c%e6%b5%81%e7%a8%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Debian Squeeze/sid + Apache + Redmine 0.9.3/trunk + MySQL + git/hg</title>
		<link>http://wangcongming.info/2010/04/debian-squeezesid-apache-redmine-0-9-3trunk-mysql-githg/</link>
		<comments>http://wangcongming.info/2010/04/debian-squeezesid-apache-redmine-0-9-3trunk-mysql-githg/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 04:31:05 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Redmine]]></category>
		<category><![CDATA[ror]]></category>

		<guid isPermaLink="false">http://wangcongming.info/?p=186</guid>
		<description><![CDATA[Update: 已可直接从库里安装了～。 # apt-get install redmine redmine-mysql libapache2-mod-passenger _________________________________________________________________________ 按：这是在公司 WIKI 上写的文章，难得这么认真，拿出来分享一下 ：）。对比过十多个项目管理系统，然后在比较好的 Redmine, Trac, Mantis 三个当中选择了 Redmine。文中以 Debian Squeeze 为例，但其它 GNU/Linux 特别是 Debian Lenny / Sid、Ubuntu 应该基本一致。 _________________________________________________________________________ 一、废话 Debian 的库里有最新的 redmine 发布版（0.9.3），一个命令就可以搞定： #apt-get install redmine However……，安装后运行会出现 http 500 service unavailable 等问题。因为 Debian 只有 2.2.3 的 rails，而 redmine 0.9.3 要求 rails 的版本为 2.3.5。 我第一个想法是，既然库里有 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update: </strong>已可直接从库里安装了～。</p>
<p># apt-get install redmine redmine-mysql libapache2-mod-passenger<br />
_________________________________________________________________________</p>
<p id="一、废话">按：这是在公司 WIKI 上写的文章，难得这么认真，拿出来分享一下 ：）。对比过十多个项目管理系统，然后在比较好的 Redmine, Trac, Mantis 三个当中选择了 Redmine。文中以 Debian Squeeze 为例，但其它 GNU/Linux 特别是 Debian Lenny / Sid、Ubuntu 应该基本一致。</p>
<p>_________________________________________________________________________</p>
<h3>一、废话</h3>
<p>Debian 的库里有最新的 redmine 发布版（0.9.3），一个命令就可以搞定：</p>
<pre>#apt-get install redmine</pre>
<p>However……，安装后运行会出现 http 500 service unavailable 等问题。因为 Debian 只有  2.2.3 的 rails，而 redmine 0.9.3 要求 rails 的版本为 2.3.5。</p>
<p>我第一个想法是，既然库里有 redmine，就不折腾了，删掉 rails，再手工装一个新版本。可是 redmine 是依赖于 rails  的，要删得一起删。然后我就想，好，保留它，再装一个新版本覆盖之！就是这个想法……，最后遇到了很多问题，又因为对 ror  不熟，在这上面浪费了不少时间。</p>
<p>没办法，全 purge 掉，实实在在从头来吧。以下以 redmine-trunk 版为例（解决了 0.9.3 中存在的 wiki+php  等一些 bug）。</p>
<p>注：以下 # 开头的命令需以 root 身份执行。</p>
<h3 id="二、依赖关系">二、依赖关系</h3>
<pre>#apt-get install ruby rubygems rake mysql-server mysql-client libmysql-ruby libopenssl-ruby
#gem install rails
</pre>
<h3 id="三、下载-redmine">三、下载 redmine</h3>
<pre>/var/projects#svn checkout http://redmine.rubyforge.org/svn/trunk redmine</pre>
<p>注：稳定发行版本下载 <a href="http://rubyforge.org/frs/?group_id=1850">http://rubyforge.org/frs/?group_id=1850</a></p>
<h3 id="四、创建数据库">四、创建数据库</h3>
<pre># mysql -u root -p
mysql&gt; create database redmine character set utf8;
mysql&gt; grant all privileges on redmine.* to redmine@localhost identified by 'PASSWORD';
</pre>
<h3 id="五、数据库配置文件">五、数据库配置文件</h3>
<pre>/var/projects/redmine#cat config/database.yml
production:
  adapter: mysql
  database: redmine
  host: localhost
  username: redmine
  password: PASSWORD
  encoding: utf8
</pre>
<h3 id="六、生成-session-key">六、生成 session key</h3>
<pre>#rake generate_session_store
</pre>
<p>会将结果写入 config/initializers/session_store.rb</p>
<h3 id="七、初始化数据库结构">七、初始化数据库结构</h3>
<pre>#RAILS_ENV=production rake db:migrate
</pre>
<h3 id="八、导入默认设置到数据库">八、导入默认设置到数据库</h3>
<pre>#RAILS_ENV=production rake redmine:load_default_data
</pre>
<h3 id="九、预览！">九、预览！</h3>
<pre>#ruby script/server webrick -e production
</pre>
<p>然后可以用浏览器访问 <a href="http://server:3000/">http://server:3000/</a> ，待测试没问题再继续。</p>
<h3 id="十、用-apache-运行-redmine">十、用 apache 运行 redmine</h3>
<p>WEBrick 虽然能跑，但是超慢！慢到无法忍受的地步（好奇的是，内存和cpu利用率都超低，它在干嘛呢……）。</p>
<p>安装：</p>
<pre>#apt-get install apache2 libapache2-mod-passenger</pre>
<p>权限：</p>
<pre>#chmod -R g+w redmine
#chown -R root:www-data redmine
</pre>
<p>符号链接：</p>
<pre>#ln -s /var/projects/redmine /var/www/redmine
</pre>
<p>配置文件：</p>
<pre>#cat /etc/apache2/conf.d/redmine
RailsEnv production
RailsBaseURI /redmine
</pre>
<p>Done:</p>
<pre>#/etc/init.d/apache reload
$firefox http://server/redmine/
</pre>
<h3 id="十一、安装修改-主题样式（可选）">十一、安装/修改 主题/样式（可选）</h3>
<p>Redmine 支持基本的主题自定义（可以覆盖默认的 css）。</p>
<p>可以到 <a href="http://www.redmine.org/wiki/redmine/Theme_List">http://www.redmine.org/wiki/redmine/Theme_List</a> 下载别人的主题包，解压后将包目录放到 public/themes/ 下面。</p>
<pre>#/etc/init.d/apache reload</pre>
<p>之后，即可访问 <a href="http://server/redmine/settings?tab=display">http://server/redmine/settings?tab=display</a> 选择新的主题。</p>
<p>不过我觉得还是默认的耐看。我直接对默认的主题做了一点修改：</p>
<pre>--- public/stylesheets/application.css    (revision 3628)
+++ public/stylesheets/application.css    (working copy)

+tr.priority-1, table.list.issues tr.priority-1 a { color: black; }
+
+tr.priority-2, table.list.issues tr.priority-2 a { color: #1c1cf3 /*similar to blue*/; }
+tr.priority-3, table.list.issues tr.priority-3 a { color: #1c1cf3; font-weight: bold; }
+
+tr.priority-4, table.list.issues tr.priority-4 a { color: red; }
+tr.priority-5, table.list.issues tr.priority-5 a { color: red; font-weight: bold; }
+
+tr.status-3, table.list.issues tr.status-3 a,
+tr.status-4, table.list.issues tr.status-4 a { color: green; font-weight: normal; }
+
+tr.status-5, table.list.issues tr.status-5 a,
+tr.status-6, table.list.issues tr.status-6 a { color: gray; font-weight: normal; }
</pre>
<p>以上加的几行，使得以不同的颜色区分不同优先级（低/高/紧急等）、不同状态（新建/进行中/反馈/已关闭等）的 issue。</p>
<h3 id="十二、安装插件（可选）">十二、安装插件（可选）</h3>
<p>很方便，下面是安装 email tls 插件的例子：</p>
<pre>#ruby script/plugin install git://github.com/collectiveidea/action_mailer_optional_tls.git</pre>
<p>更新数据库：</p>
<pre>#RAILS_ENV=production rake db:migrate:upgrade_plugin_migrations
#RAILS_ENV=production rake db:migrate_plugins
</pre>
<h3 id="十三、配置-email-发送功能-——-任务建立变更时，发送邮件提醒（可选）">十三、配置 email 发送功能 ——  任务建立/变更时，发送邮件提醒（可选）</h3>
<p>以 GMail 为例，先要安装上一步提到的 email 插件，然后:</p>
<pre>#cat config/email.yml
production:
  delivery_method: :smtp
  smtp_settings:
    tls: true
    address: "smtp.gmail.com"
    port: 587
    domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps
    authentication: :plain
    user_name: "xxxxx@gmail.com"
    password: "xxxxxxxxxxxxxxxx"
</pre>
<p>完了 reload apache 即可。这里 <a href="http://server/redmine/settings?tab=notifications">http://server/redmine/settings?tab=notifications</a> 有一些设置选项。我去掉了 bcc，选中了纯文本。</p>
<p>修改 1:</p>
<pre>--- app/models/mailer.rb    (revision 3628)
+++ app/models/mailer.rb    (working copy)
-    subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
+    subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.subject}" 

     s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
-    s &lt;&lt; "(#{issue.status.name}) " if journal.new_value_for('status_id')
     s &lt;&lt; issue.subject
</pre>
<p>修改的目的，是使得 redmine 发送的邮件提醒在标题中不要包含 issue  的状态（新建/进行中/已关闭等），从而使得关于同一个问题的所有提醒邮件在 GMail 中都能自动组织成一个会话，非常有利于上下文的理解。</p>
<p>redmine 默认在邮件标题中包含 issue 的状态信息，使得每一次状态变更的邮件都分散到不同的会话中，很讨厌。</p>
<p>修改 2:</p>
<pre>--- config/locales/zh.yml    (revision 3628)
+++ config/locales/zh.yml    (working copy)
-  text_journal_changed: "{{label}} 从 {{old}} 变更为 {{new}}"
-  text_journal_set_to: "{{label}} 被设置为 {{value}}"
-  text_journal_deleted: "{{label}} 已删除 ({{old}})"
-  text_journal_added: "{{label}} {{value}} 已添加"
+  text_journal_changed: "{{label}}：{{old}} -&gt; {{new}}"
+  text_journal_set_to: "{{label}}： -&gt; {{value}}"
+  text_journal_deleted: "已删除：{{label}} ({{old}})"
+  text_journal_added: "已添加：{{label}} {{value}}"
</pre>
<p>对中文翻译的一点修改，这是邮件提醒中对 issue 变更的说明，我觉得太啰嗦了，不直观明了，没有重点。</p>
<p>注：如果你发现发出去的邮件，issue 链接都是带 3000 端口号的，而你现在用 apache 跑 redmine  不需要端口号，可以去 <a href="http://server/redmine/settings">http://server/redmine/settings</a> 改“主机名称”。这是因为你第九步的时候无意中保存过这个设置。</p>
<h3 id="十四、打-patch（可选）">十四、打 patch（可选）</h3>
<p>以下是作者提供的一个 patch，使得在 redmine  中，可以将任务指派给一个组/group，该组的所有成员都会收到邮件提醒（只是，该任务不会显示在“我的工作台”里）。</p>
<pre>redmine#wget http://www.redmine.org/attachments/download/2965/0001-Allow-issues-to-be-assigned-to-a-Group.-2964.patch
redmine#patch -p1 &lt; 0001-Allow-issues-to-be-assigned-to-a-Group.-2964.patch
</pre>
<p>注一：执行 patch 的时候，它会有一点小抱怨，可不予理会。</p>
<p>注二：<a href="http://server/redmine/groups">http://server/redmine/groups</a> ，此处可以增删/编辑小组及其成员。</p>
<h3 id="十五、与版本控制软件集成（githg）">十五、与版本控制软件集成（Git / Mercurial）</h3>
<p>配置系统（使得只有组内的成员才可以查看/修改项目代码，不同的项目使用不同的组）：</p>
<pre>#groupadd saas
#echo 'if [ "saas" == "$(id -gn $(whoami))" ]; then umask 007; fi' &gt;&gt; /etc/profile
</pre>
<p><strong>Update：</strong><br />
在 /etc/profile 中设置 umask 只会影响 login shell，而我们通过 git push 过来的文件仍然是默认的  755 权限（修改 .bashrc 等亦无效）。</p>
<p>要设置 git push 到服务器的文件的权限为 770（同组成员可写），正确的做法是：</p>
<pre># echo "session optional pam_umask.so umask=007" &gt;&gt; /etc/pam.d/common-session</pre>
<p>此外，以下方法应该也可以（没有测试）：</p>
<pre># echo "Subsystem git /bin/bash -c 'umask 007; /usr/bin/git'" &gt;&gt; /etc/ssh/sshd_config</pre>
<p>安装 git：</p>
<pre>#apt-get install git-core</pre>
<p>初始化 git 版本库：</p>
<pre>#mkdir /var/projects/saas
#cd /var/projects/saas
#git --bare init
#chown -R root:saas ../saas
#chmod -R 770 ../saas
</pre>
<p>版本库初始化完成，若要增加新的开发者（各自使用自己的帐号），由管理员执行：</p>
<pre>#useradd -m -s /bin/bash -g saas username # 注意，若不指定，默认的 dash 会出错
</pre>
<p>并将其 pub key 添加到 /home/username/.ssh/authorized_keys 之内。</p>
<p>开发人员在客户端的操作：</p>
<pre>$git config --global user.name "xxx yyy"
$git config --global user.email "xxx@gmai.com"
$git clone username@server:/var/projects/saas
</pre>
<p>测试：</p>
<pre>$cd saas
$echo hello &gt; world
$git add .
$git commit -a -m 'hello world'
$git push origin master
</pre>
<p>以后再 push，就不需要 “origin master” 这两个参数了。</p>
<p>最后，因为初始化版本库的时候我们用了 &#8211;bare 参数，在 /var/projects/saas 下是看不到项目代码文件的。</p>
<p>可以生成一份代码拷贝，用来在 apache 下进行测试：</p>
<pre>#cd /var/www
#git clone /var/projects/saas
#chown -R root:saas saas
#chmod -R 770 saas
#addgroup www-data saas
</pre>
<p>开发者 push 完后，apache 下的代码并不会自动更新，若想测试（这个测试相当于预览，因为开发人员 push  之前是需要先在自己的机器上认真测试的）更新后的代码：</p>
<pre>/var/www/saas$git pull # 注意，各用自己的帐号执行，不要用 root
</pre>
<p>至此，版本管理系统已经正常工作，还剩最后一件事：那就是告诉 Redmine，我们版本库的路径。</p>
<p>浏览器里打开 Redmine，新建一个项目，然后在“设置”里会有个标签叫“版本库”，选择 git，并在 path 里填  /var/projects/saas 就搞定了！</p>
<p>另，hg 的设置与 git 非常相似，大部分参数都一样，不另述。</p>
<h3 id="十六、升级-redmine-svn-trunk（可选）">十六、升级 redmine svn trunk（可选）</h3>
<pre>#svn update
#rake tmp:cache:clear
#rake tmp:sessions:clear
</pre>
<p>可能还要执行第七步和第十二步提到的更新数据库的操作。升级之前应该先备份，在测试实例上确认没有问题再升级。</p>
<h3 id="十七、备份redmine数据">十七、备份redmine数据</h3>
<p>一是数据库：</p>
<pre>#mysqldump -u redmine -p redmine &gt; redmine.$(date +%F).sql</pre>
<p>二是上传的文件：</p>
<pre>/var/projects/redmine#tar cvzf ../redmine.uploaded.files.$(date +%F).tar.gz files/</pre>
<p>（完）</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2010/04/debian-squeezesid-apache-redmine-0-9-3trunk-mysql-githg/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>两个小问题（lcrypto, Py_InitModule4），记录一下～</title>
		<link>http://wangcongming.info/2008/04/%e4%b8%a4%e4%b8%aa%e5%b0%8f%e9%97%ae%e9%a2%98%ef%bc%88lcrypto-py_initmodule4%ef%bc%89%ef%bc%8c%e8%ae%b0%e5%bd%95%e4%b8%80%e4%b8%8b%ef%bd%9e/</link>
		<comments>http://wangcongming.info/2008/04/%e4%b8%a4%e4%b8%aa%e5%b0%8f%e9%97%ae%e9%a2%98%ef%bc%88lcrypto-py_initmodule4%ef%bc%89%ef%bc%8c%e8%ae%b0%e5%bd%95%e4%b8%80%e4%b8%8b%ef%bd%9e/#comments</comments>
		<pubDate>Mon, 21 Apr 2008 10:21:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[avant]]></category>
		<category><![CDATA[fitx]]></category>
		<category><![CDATA[openssl]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2008/04/21/%e4%b8%a4%e4%b8%aa%e5%b0%8f%e9%97%ae%e9%a2%98%ef%bc%88lcrypto-py_initmodule4%ef%bc%89%ef%bc%8c%e8%ae%b0%e5%bd%95%e4%b8%80%e4%b8%8b%ef%bd%9e/</guid>
		<description><![CDATA[一、cannot find -lcrypto 编译 fitx 时遇到的。一番 Google 之后，原来是指 libcrypto.so，而这个库属于 libssl-dev 包。 依赖里没有提这个包，装上后就没事了。 PS：因为 scim-python 是直接 make install 的，没有打包。fitx 依赖于 scim-python，我没有改依赖关系，而是用 dpkg -i &#8211;force- 安装。然后dpkg给出提示说： dpkg：fitx：尽管有依赖关系的问题，但不管怎样，还是按照您的要求，继续配置： 不知怎的，我觉得这段话很好玩。有一种幽默感、亲切感、尊重感，还有……~~~ 二、undefined symbol: Py_InitModule4 运行 awn-manager 时遇到的。这是配置错误，/usr/bin/awn-manager： SITE_PKG = &#8216;/usr/lib/python2.4/site-packages&#8217; 将其中的2.4改成2.5就OK了。 原因是，python2.5 中，﻿将 64bit 系统下的 Py_InitModule4 改名为 Py_InitModule4_64 了。改名目的是为了阻止2.4的模块调用2.5的解析器。因为2.5针对64bit机做了不兼容于2.4的修改，以支持 4GB+ 内存。 #if SIZEOF_SIZE_T != SIZEOF_INT /* On a 64-bit system, [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight: bold;">一、cannot find -lcrypto</span><br />
编译 fitx 时遇到的。一番 Google 之后，原来是指 libcrypto.so，而这个库属于 libssl-dev 包。<br />
依赖里没有提这个包，装上后就没事了。</p>
<p>PS：因为 scim-python 是直接 make install 的，没有打包。fitx 依赖于 scim-python，我没有改依赖关系，而是用 dpkg -i &#8211;force- 安装。然后dpkg给出提示说：</p>
<blockquote><p>dpkg：fitx：尽管有依赖关系的问题，但不管怎样，还是按照您的要求，继续配置：</p>
</blockquote>
<p>不知怎的，我觉得这段话很好玩。有一种幽默感、亲切感、尊重感，还有……~~~</p>
<p><span style="font-weight: bold;">二、undefined symbol: Py_InitModule4</span><br />
运行 awn-manager 时遇到的。这是配置错误，/usr/bin/awn-manager：</p>
<blockquote><p>SITE_PKG = &#8216;/usr/lib/python2.4/site-packages&#8217;</p>
</blockquote>
<p>将其中的2.4改成2.5就OK了。</p>
<p>原因是，python2.5 中，﻿将 64bit 系统下的 Py_InitModule4 改名为 Py_InitModule4_64 了。改名目的是为了阻止2.4的模块调用2.5的解析器。因为2.5针对64bit机做了不兼容于2.4的修改，以支持 4GB+ 内存。</p>
<blockquote><p>#if SIZEOF_SIZE_T != SIZEOF_INT<br />
/* On a 64-bit system, rename the Py_InitModule4 so that 2.4 modules cannot get loaded into a 2.5 interpreter */<br />
#define Py_InitModule4 Py_InitModule4_64<br />
#endif</p>
</blockquote>
<p><a href="http://svn.python.org/projects/python/trunk/include/modsupport.h">http://svn.python.org/projects/python/trunk/Include/modsupport.h</a></p>
<blockquote><p>In Python 2.4, indices of sequences are restricted to the C type int. On 64-bit machines, sequences therefore cannot use the full address space, and are restricted to 2**31 elements. This PEP proposes to change this, introducing a platform-specific index type Py_ssize_t.</p>
<p>As the proposed change will cause incompatibilities on 64-bit machines, it should be carried out while such machines are not in wide use (IOW, as early as possible).</p>
</blockquote>
<p><a href="http://www.python.org/dev/peps/pep-0353/">http://www.python.org/dev/peps/pep-0353/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2008/04/%e4%b8%a4%e4%b8%aa%e5%b0%8f%e9%97%ae%e9%a2%98%ef%bc%88lcrypto-py_initmodule4%ef%bc%89%ef%bc%8c%e8%ae%b0%e5%bd%95%e4%b8%80%e4%b8%8b%ef%bd%9e/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Netscape/Mozilla 趣史</title>
		<link>http://wangcongming.info/2008/01/netscapemozilla-%e8%b6%a3%e5%8f%b2/</link>
		<comments>http://wangcongming.info/2008/01/netscapemozilla-%e8%b6%a3%e5%8f%b2/#comments</comments>
		<pubDate>Sun, 27 Jan 2008 12:26:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[AOL]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[history]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[mascot]]></category>
		<category><![CDATA[Mosaic]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Netscape]]></category>
		<category><![CDATA[User-Agent]]></category>
		<category><![CDATA[WEB]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2008/01/27/netscapemozilla-%e8%b6%a3%e5%8f%b2/</guid>
		<description><![CDATA[按：今天被“Mozilla 的圣经”勾起了兴趣，进而了解了更多一些历史。现简单记录一下，也算是对 Netscape 历经14年风雨动荡并终于在2008年初寿终正寝的一点纪念和致敬吧。 一、Netscape/Mozilla 是谁？ 对于年纪不大且不大关心 WEB 的人来说，这个问题是很正常的。 非严格来说，Netscape（网景）是一个公司及其出品的 WEB 浏览器的名字。正是这个浏览器吸引并教育了最早的一批万维网用户，并且创造和引进了许多至今仍在应用的 WEB 技术和标准。 众所周知的是，Netscape 最终被微软的 IE（Internet Explorer）干掉了。 1998年，Netscape 被 AOL（美国在线）以4百20万美元的价格收购（微软败诉于反垄断案后，AOL 籍此获得了7.5亿的赔偿），后 AOL 又被 TimeWarner（时代华纳）收购。 AOL 在获得巨额赔偿的同时，还吃了微软一个“７年内可以无限制使用和散布IE”的糖衣炮弹。 2003年，网景终于被宣布解散，只剩少部分人继续维护和开发。 2008年初，Netscape 的开发被宣布彻底终止，并将于 2008.2.1 停止所有安全与技术支持。 如果只是这样，那也无甚好说。传奇的是，Netscape 在卖掉的前夕创立了开源的 Mozilla 社区，而后者诞生了另一款革命性的浏览器（firefox）。形象地说，Netscape 的躯体已经死了，而血脉流传到了 Mozilla。 二、Mozilla 吉祥物 Mozilla 在作为开源计划的名称之前，早已在 Netscape 使用多年，包括作为开发代号、作为吉祥物（那是一只类暴龙，原先是绿色，现在进化到了红色）等。 以下有很多 Mozilla 吉祥物的卡通图，有些满 funny 的。 The Mozilla Museum: http://home.snafu.de/tilman/mozilla/ Dave Titus（Mozilla [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight: bold;">按：</span>今天被“Mozilla 的圣经”勾起了兴趣，进而了解了更多一些历史。现简单记录一下，也算是对 Netscape 历经14年风雨动荡并终于在2008年初寿终正寝的一点纪念和致敬吧。</p>
<p><span style="font-weight: bold;">一、Netscape/Mozilla 是谁？</span></p>
<p>对于年纪不大且不大关心 WEB 的人来说，这个问题是很正常的。</p>
<p>非严格来说，<a href="http://zh.wikipedia.org/wiki/Netscape">Netscape</a>（网景）是一个公司及其出品的 WEB 浏览器的名字。正是这个浏览器吸引并教育了最早的一批万维网用户，并且创造和引进了许多至今仍在应用的 WEB 技术和标准。</p>
<p>众所周知的是，Netscape 最终被微软的 IE（Internet Explorer）干掉了。</p>
<p style="padding-left: 20px; font-size: 90%;">1998年，Netscape 被 <a href="http://zh.wikipedia.org/wiki/AOL">AOL</a>（美国在线）以4百20万美元的价格收购（微软败诉于反垄断案后，AOL 籍此获得了7.5亿的赔偿），后 AOL 又被 <a href="http://zh.wikipedia.org/wiki/时代华纳">TimeWarner</a>（时代华纳）收购。</p>
<p>AOL 在获得巨额赔偿的同时，还吃了微软一个“７年内可以无限制使用和散布IE”的糖衣炮弹。<br />
2003年，网景终于被宣布解散，只剩少部分人继续维护和开发。</p>
<p>2008年初，Netscape 的开发被宣布彻底终止，并将于 2008.2.1 停止所有安全与技术支持。</p>
<p>如果只是这样，那也无甚好说。传奇的是，Netscape 在卖掉的前夕创立了开源的 <a href="http://www.mozilla.org/">Mozilla</a> 社区，而后者诞生了另一款革命性的浏览器（<a href="http://www.mozilla.com/en-US/firefox/">firefox</a>）。形象地说，Netscape 的躯体已经死了，而血脉流传到了 Mozilla。</p>
<p><span style="font-weight: bold;">二、Mozilla 吉祥物</span></p>
<p>Mozilla 在作为开源计划的名称之前，早已在 Netscape 使用多年，包括作为开发代号、作为吉祥物（那是一只类暴龙，原先是绿色，现在进化到了红色）等。</p>
<p style="padding-left: 20px; font-size: 90%;">以下有很多 Mozilla 吉祥物的卡通图，有些满 funny 的。</p>
<p>The Mozilla Museum:<br />
<a href="http://home.snafu.de/tilman/mozilla/">http://home.snafu.de/tilman/mozilla/</a></p>
<p><a href="http://www.davetitus.com/">Dave Titus</a>（Mozilla 卡通形象的设计者） T-Shirt collection:<br />
<a href="http://www.ex-mozilla.org/teeshirtart/">http://www.ex-mozilla.org/teeshirtart/</a></p>
<p><span style="font-weight: bold;">三、图形网页浏览器的鼻祖 ＆ Mozilla 名字的来源</span></p>
<p>虽然 Netscape 在早期很有影响力，但史上第一个图形化的 Web 浏览器应该是 <a href="http://zh.wikipedia.org/wiki/Mosaic">Mosaic</a>。它由 <a href="http://zh.wikipedia.org/wiki/NCSA">NCSA</a>（National Center for Supercomputing Applications，美国国家超级计算应用中心，设立于<a href="http://zh.wikipedia.org/wiki/伊利诺大学">伊利诺大学</a>）发布于1993年。早年的领头羊 Netscape 以及现时的霸主 IE 虽没有直接使用它的源码，但都与之有很深的渊源。</p>
<p style="padding-left: 20px; font-size: 90%;">对此感兴趣的话，可以看看 IE 原作者的回忆文章。<br />
Memoirs From the Browser Wars：<a href="http://www.ericsink.com/Browser_Wars.html">http://www.ericsink.com/Browser_Wars.html</a></p>
<p>而 Mozilla 的名字即是由 Mosaic 杀手（Mosaic killer）变化而来（Moz+illa）。</p>
<p><span style="font-weight: bold;">四、Mozilla 的圣经</span></p>
<p>显然，Mozilla 并没有出版过这么一本书。然而，如果你使用 Netscape 或者 firefox 的话，只需在地址栏输入“about:mozilla”即会看到一段很有启示文学风格的引文，引文的最后注明“from The Book of Mozilla”，使人误以为真有其书。最后会注明一个时间，这个时间代表一个 Mozilla 的重要日期。不同版本的浏览器可能会有不同的引文。</p>
<p>比如，我现在的版本（IceWeasel 2.0.0.11）是这样的的：</p>
<p><a href="http://2.bp.blogspot.com/_RtqRASEBtF8/R51znykHH0I/AAAAAAAAAkE/7lsVlDca5sw/s1600-h/The+Books+of+Mozilla.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img id="BLOGGER_PHOTO_ID_5160407875461783362" style="display: block; margin: 0; text-align: left; cursor: pointer;" src="http://2.bp.blogspot.com/_RtqRASEBtF8/R51znykHH0I/AAAAAAAAAkE/7lsVlDca5sw/s400/The+Books+of+Mozilla.jpg" border="0" alt="The Book of Mozilla" /></a></p>
<div style="background: maroon; font-style: italic; padding: 2em 1em; margin: 0;">
<p style="font-family: sans-serif; color: #fff; line-height: 1.6;">最后野兽终于<em style="font-size: 120%; padding-left: 0.1em;">沒落</em>，异教徒们欢欣鼓舞。不过一切并没有结束，因为灰烬中飞出一只<em style="font-size: 120%; padding-left: .1em;">巨鸟</em>。那只鸟望向不信者，并将<em style="font-size: 120%; padding-left: .1em;">火</em>与<em style="font-size: 120%; padding-left: .1em;">雷</em>加诸他们身上。野兽已经<em style="font-size: 120%; padding-left: .1em;">重生</em>，力量<em style="font-size: 120%; padding-left: .1em;">更甚强大</em>，<em style="font-size: 120%; padding-left: .1em;">玛门</em>的追随者仓皇逃逸。</p>
<p style="font-size: 180%; color: white; font-family: serif; text-align: right;">來自<strong> Mozilla 之書</strong>，7:15</p>
</div>
<p>7:15 这章节指代2003年7月15日，即 Netscape 被解散、Mozilla 基金会成立的日期。<br />
野兽的没落指 Netscape 的解散；Mozilla 这只巨鸟在浴火中重生；火与雷指代 Mozilla 的两个旗舰产品：Firebird（Firefox 的原名）、Thunderbird；Netscape 的理念在 Mozilla 基金会“重生”，不再像从前那么依赖AOL，力量变得“更强”；玛门指代微软。</p>
<p style="padding-left: 20px; font-size: 90%;">细细读来，觉得确实蛮坎坷顽强的。如果有兴趣可以在下面站点找到其它章节。</p>
<p>Mozilla 官方站点，注意看源代码，有注释：<br />
<a href="http://www.mozilla.org/book/">http://www.mozilla.org/book/</a></p>
<p>英文维基页面，比官方站点多两个，并且有浏览器截图：<br />
<a href="http://en.wikipedia.org/wiki/The_Book_of_Mozilla">http://en.wikipedia.org/wiki/The_Book_of_Mozilla</a></p>
<p>中文维基页面，目前比英文维基少两个，没有截图但有中文解释：<br />
<a href="http://zh.wikipedia.org/wiki/Mozilla之书">http://zh.wikipedia.org/wiki/Mozilla之书</a></p>
<p><span style="font-weight: bold;">五、User Agent String，IE 的童年</span></p>
<p>以前一直有个疑问，为什么 IE 的特征串会包含 “Mozilla” 这个词，难不成 IE 初始时用了 Netscape 的代码？</p>
<p>原来，因为早先 Netscape 非常 NB，很多网站都 Designed Only for Netscape。通过检测客户端特征串识别 Netscape 的浏览器，对其它的浏览器要么不理，要么只给点阉割的功能（怎么这么熟悉，风水轮流转呵）。IE 为了能访问这些站点，就搞起了特征串欺骗，说“我是 Netscape 啊，不要歧视我啊”。。。</p>
<p style="padding-left: 20px; font-size: 90%;">即使后来 IE 成了新的霸主，”Mozilla” 的字眼依然保留在 IE 的特征串中，微软还是满坦然的～。</p>
<p>IE 还有一个对 Netscape 的恶搞动作。因为 Netscape 能通过 “about:Mozilla” 阅读 “The Book of Mozilla”，据说，在早期的 IE 中输入 “about:Mozilla” 也有个页面——象征死机的蓝屏。</p>
<p>呵呵，史海轮回，Netscape 一路走好，Firefox 加油！</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2008/01/netscapemozilla-%e8%b6%a3%e5%8f%b2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>杂碎笔记：DOM中的Text节点</title>
		<link>http://wangcongming.info/2007/09/%e6%9d%82%e7%a2%8e%e7%ac%94%e8%ae%b0%ef%bc%9adom%e4%b8%ad%e7%9a%84text%e8%8a%82%e7%82%b9/</link>
		<comments>http://wangcongming.info/2007/09/%e6%9d%82%e7%a2%8e%e7%ac%94%e8%ae%b0%ef%bc%9adom%e4%b8%ad%e7%9a%84text%e8%8a%82%e7%82%b9/#comments</comments>
		<pubDate>Sun, 23 Sep 2007 15:27:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2007/09/23/%e6%9d%82%e7%a2%8e%e7%ac%94%e8%ae%b0%ef%bc%9adom%e4%b8%ad%e7%9a%84text%e8%8a%82%e7%82%b9/</guid>
		<description><![CDATA[DOM中的Text节点，has no properties错误 考虑下面一段代码： &#60;script type=”text/javascript”&#62; function switch_nextSibling_display(hdl){ hdl=hdl.nextSibling; if(hdl.style.display==”none”) hdl.style.display=”block”; else hdl.style.display=”none”; } &#60;/script&#62; &#60;input type=”button” value=”Click Me!” onclick=”switch_nextSibling_display(this)”/&#62; &#60;input type=”button” value=”Hidding Me!”/&#62; 能得到我们想要的结果吗？否！如果用firebug调试的话（有了firebug太爽了哈～），会得到“……has no properties”的提示。这是因为：两个 input 控件之间有个换行符。在DOM树中，包括换行符、空格及其他普通字符都属于Text节点。不能因为换行符和空格看不见就当它不存在，实际上，前 input 节点的 nextSibling 正是这个Text节点，应该nextSibling.nextSibling才对。不过，在IE中，这个Text节点是被忽略的。为了兼容，有两个方法，一就是不要换行；或者，加上这么一句：if(hdl.nodeType==3) hdl=hdl.nextSibling，nodeType等于3表示Text节点。 P的问题～ 同样是上面的script，下面的click能预期执行吗？ &#60;input type=”button” value=”Click Me!” onclick=”switch_nextSibling_display(this)”/&#62;&#60;p&#62;I want to hide&#60;p&#62;all this!&#60;/p&#62;&#60;/p&#62; 同样不能，”all this”是不受影响的。虽然看起来，后一个p只是前一个p的子节点，好像前面的p包括整句话才能称的上是input的“兄弟”。但实际上，p是不能自包含的，当后一个p出现的时候，前一个p就被关闭了，所以那句话等价于：&#60;p&#62;I want to hide&#60;/p&#62;&#60;p&#62;all this!&#60;/p&#62;。同理，p也不能包含div等块级元素。虽然手工不大可能写出这样的语句，但一些半自动的场合难免，这时用JS读/写DOM树可能会碰到一些意想不到的问题。 var与非var JavaScript中，在函数外用不用var定义的变量都是全局的，在函数内部，var定义局部变量，不用var定义全局变量，这似乎没什么问题。但下面一段代码会alert出什么呢？ &#60;script type="text/javascript"&#62;var [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight: bold;">DOM中的Text节点，has no properties错误</span></p>
<p>考虑下面一段代码：</p>
<div style="margin-left: 20px;">&lt;script type=”text/javascript”&gt;<br />
function switch_nextSibling_display(hdl){<br />
hdl=hdl.nextSibling;<br />
if(hdl.style.display==”none”) hdl.style.display=”block”;<br />
else hdl.style.display=”none”;<br />
}<br />
&lt;/script&gt;<br />
&lt;input type=”button” value=”Click Me!” onclick=”switch_nextSibling_display(this)”/&gt;<br />
&lt;input type=”button” value=”Hidding Me!”/&gt;</div>
<p>能得到我们想要的结果吗？否！如果用firebug调试的话（有了firebug太爽了哈～），会得到“……has no properties”的提示。这是因为：两个 input 控件之间有个换行符。在DOM树中，包括换行符、空格及其他普通字符都属于Text节点。不能因为换行符和空格看不见就当它不存在，实际上，前 input 节点的 nextSibling 正是这个Text节点，应该nextSibling.nextSibling才对。不过，在IE中，这个Text节点是被忽略的。为了兼容，有两个方法，一就是不要换行；或者，加上这么一句：if(hdl.nodeType==3) hdl=hdl.nextSibling，nodeType等于3表示Text节点。</p>
<p><span style="font-weight: bold;">P的问题～</span><br />
同样是上面的script，下面的click能预期执行吗？</p>
<div style="margin-left: 20px;">&lt;input type=”button” value=”Click Me!” onclick=”switch_nextSibling_display(this)”/&gt;&lt;p&gt;I want to hide&lt;p&gt;all this!&lt;/p&gt;&lt;/p&gt;</div>
<p>同样不能，”all this”是不受影响的。虽然看起来，后一个p只是前一个p的子节点，好像前面的p包括整句话才能称的上是input的“兄弟”。但实际上，p是不能自包含的，当后一个p出现的时候，前一个p就被关闭了，所以那句话等价于：&lt;p&gt;I want to hide&lt;/p&gt;&lt;p&gt;all this!&lt;/p&gt;。同理，p也不能包含div等块级元素。虽然手工不大可能写出这样的语句，但一些半自动的场合难免，这时用JS读/写DOM树可能会碰到一些意想不到的问题。</p>
<p><span style="font-weight: bold;">var与非var</span><br />
JavaScript中，在函数外用不用var定义的变量都是全局的，在函数内部，var定义局部变量，不用var定义全局变量，这似乎没什么问题。但下面一段代码会alert出什么呢？</p>
<pre style="margin-left: 20px;">&lt;script type="text/javascript"&gt;var a=1;function f(){   alert(a);   var a=2;}f();&lt;/script&gt;</pre>
<p>1吗？No。因为f()里面声明了与全局变量同名的局部变量，代码在运行前先处理变量声明，所以此a已非彼a了，但是alert的时候a还没有被赋值，所以结果是undefined。倘若把f()里面的声明：var a=2 改成赋值：a=2，此a就仍然是彼a，此时因为a的值尚未被改变，所以结果是1。另，全局的JS变量还能被VBScript访问。</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2007/09/%e6%9d%82%e7%a2%8e%e7%ac%94%e8%ae%b0%ef%bc%9adom%e4%b8%ad%e7%9a%84text%e8%8a%82%e7%82%b9/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>修正Debian下的“Could not open default cursor font &#8216;cursor&#8217;”错误</title>
		<link>http://wangcongming.info/2007/08/%e4%bf%ae%e6%ad%a3debian%e4%b8%8b%e7%9a%84%e2%80%9ccould-not-open-default-cursor-font-cursor%e2%80%9d%e9%94%99%e8%af%af/</link>
		<comments>http://wangcongming.info/2007/08/%e4%bf%ae%e6%ad%a3debian%e4%b8%8b%e7%9a%84%e2%80%9ccould-not-open-default-cursor-font-cursor%e2%80%9d%e9%94%99%e8%af%af/#comments</comments>
		<pubDate>Sun, 05 Aug 2007 04:27:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[Debian]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2007/08/05/%e4%bf%ae%e6%ad%a3debian%e4%b8%8b%e7%9a%84%e2%80%9ccould-not-open-default-cursor-font-cursor%e2%80%9d%e9%94%99%e8%af%af/</guid>
		<description><![CDATA[昨晚折腾Debian，最后弄出个致命错误，导致X无法启动 错误信息： fatal error: Could not open default cursor font &#8216;cursor&#8217; 最终从Debian邮件列表里搜到了答案，只需装上“artwiz－cursor”字体包就OK了 console下： # aptitude install artwiz-cursor done!]]></description>
			<content:encoded><![CDATA[<p>昨晚折腾Debian，最后弄出个致命错误，导致X无法启动</p>
<p>错误信息：<br />
fatal error: Could not open default cursor font &#8216;cursor&#8217;</p>
<p>最终从Debian邮件列表里搜到了答案，只需装上“artwiz－cursor”字体包就OK了<br />
console下：<br />
# aptitude install artwiz-cursor<br />
done!</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2007/08/%e4%bf%ae%e6%ad%a3debian%e4%b8%8b%e7%9a%84%e2%80%9ccould-not-open-default-cursor-font-cursor%e2%80%9d%e9%94%99%e8%af%af/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用TestDisk恢复分区表</title>
		<link>http://wangcongming.info/2007/08/%e7%94%a8testdisk%e6%81%a2%e5%a4%8d%e5%88%86%e5%8c%ba%e8%a1%a8/</link>
		<comments>http://wangcongming.info/2007/08/%e7%94%a8testdisk%e6%81%a2%e5%a4%8d%e5%88%86%e5%8c%ba%e8%a1%a8/#comments</comments>
		<pubDate>Sat, 04 Aug 2007 05:28:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[TestDisk]]></category>
		<category><![CDATA[分区表]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2007/08/04/%e7%94%a8testdisk%e6%81%a2%e5%a4%8d%e5%88%86%e5%8c%ba%e8%a1%a8/</guid>
		<description><![CDATA[一不小心把移动硬盘的分区表给弄坏了，那可是命根子啊！ 分区表虽然坏了，但是并没有格式化，数据还是在的，我想有没有工具可以自动检测并还原正确的分区信息呢？ 呵呵，那就是TestDisk了！基本上，听说过的分区格式都支持～ 在Debian下直接 “sudo apt-get install testdisk”， 然后确认几下就OK了。 好东东，很好，很强大～～～]]></description>
			<content:encoded><![CDATA[<p>一不小心把移动硬盘的分区表给弄坏了，那可是命根子啊！</p>
<p>分区表虽然坏了，但是并没有格式化，数据还是在的，我想有没有工具可以自动检测并还原正确的分区信息呢？</p>
<p>呵呵，那就是TestDisk了！基本上，听说过的分区格式都支持～</p>
<p>在Debian下直接 “sudo apt-get install testdisk”，<br />
然后确认几下就OK了。</p>
<p>好东东，很好，很强大～～～</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2007/08/%e7%94%a8testdisk%e6%81%a2%e5%a4%8d%e5%88%86%e5%8c%ba%e8%a1%a8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>adblock隐藏规则中的CSS选择器</title>
		<link>http://wangcongming.info/2007/06/adblock%e9%9a%90%e8%97%8f%e8%a7%84%e5%88%99%e4%b8%ad%e7%9a%84css%e9%80%89%e6%8b%a9%e5%99%a8/</link>
		<comments>http://wangcongming.info/2007/06/adblock%e9%9a%90%e8%97%8f%e8%a7%84%e5%88%99%e4%b8%ad%e7%9a%84css%e9%80%89%e6%8b%a9%e5%99%a8/#comments</comments>
		<pubDate>Sat, 30 Jun 2007 04:08:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[adblock]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[广告]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2007/06/30/adblock%e9%9a%90%e8%97%8f%e8%a7%84%e5%88%99%e4%b8%ad%e7%9a%84css%e9%80%89%e6%8b%a9%e5%99%a8/</guid>
		<description><![CDATA[adblock（官网、安装）是我觉得最不可或缺的几个Firefox 插件之一，除了过滤用于广告的帧、脚本、图片、flash等，加快浏览速度之外，元素隐藏则可以隐藏那些恶心的文本广告，清新整洁的互联网使人心情愉悦：），想到一句广告词：痘痘都不见了！ 然而，这次却遇到一个极想隐藏又没办法隐藏的广告。因为人家只有一个table，总不至于把所有table都隐藏了吧=_=! 我只好再次打开adblock官网，找到过滤规则写法说明，看看会不会有什么新发现。虽然早就看过，但只是草草概览了一遍，这回认真一看，果然以前漏掉了一个极重要的特性：adblock支持 CSS selector 。 也就是说，就好像自己就是这个网站的作者，像平常写style sheet一样选择元素，最后由adblock自动在后面加上{ display: none; }。比如： Click the expand button to read full text&#8230; * //匹配所有元素 A //匹配所有名为A的元素 A B //匹配名为B且包含在A中的元素（B是A的“后代”，包括儿子、孙子……） A&#62;B /* 匹配名为B且是A的孩子的元素： &#60;div&#62;Hello&#60;h1&#62;adblock, &#60;em&#62;I love you!&#60;/em&#62;&#60;/h1&#62;&#60;/div&#62; 其中，h1是div的孩子，em是div的孙子…… div&#62;h1：匹配 div&#62;em：不匹配 div em：匹配 */ A:first-child /* 匹配名为A且是其父母长子的元素 &#60;h1&#62;&#60;strong&#62;Hello&#60;/strong&#62;&#60;em&#62;adblock!&#60;/em&#62;&#60;/h1&#62; 其中，strong是长子，em不是 strong:first-child：匹配 em:first-child：不匹配 */ A + B /* 匹配名为B且是A紧挨着的弟弟的元素 &#60;nl&#62; &#60;lable&#62;for [...]]]></description>
			<content:encoded><![CDATA[<p>adblock（<a href="http://adblockplus.org/en/">官网</a>、<a href="https://addons.mozilla.org/en-US/firefox/addon/1865">安装</a>）是我觉得最不可或缺的几个<a href="http://www.mozilla.org.cn/">Firefox</a> <a href="https://addons.mozilla.org/en-US/firefox/">插件</a>之一，除了过滤用于广告的帧、脚本、图片、flash等，加快浏览速度之外，元素隐藏则可以隐藏那些恶心的文本广告，清新整洁的互联网使人心情愉悦：），想到一句广告词：痘痘都不见了！</p>
<p>然而，这次却遇到一个极想隐藏又没办法隐藏的广告。因为人家只有一个table，总不至于把所有table都隐藏了吧=_=!</p>
<p>我只好再次打开adblock官网，找到<a href="http://adblockplus.org/en/filters">过滤规则写法说明</a>，看看会不会有什么新发现。虽然早就看过，但只是草草概览了一遍，这回认真一看，果然以前漏掉了一个极重要的特性：adblock支持 <a href="http://www.w3.org/TR/REC-CSS2/selector.html">CSS selector</a> 。</p>
<p>也就是说，就好像自己就是这个网站的作者，像平常写style sheet一样选择元素，最后由adblock自动在后面加上{ display: none; }。比如：</p>
<p><span class="note_text">Click the expand button to read full text&#8230;</span><span class="long_text"><span class="code"><br />
*<br />
//匹配所有元素</span></span></p>
<p>A<br />
//匹配所有名为A的元素</p>
<p>A B<br />
//匹配名为B且包含在A中的元素（B是A的“后代”，包括儿子、孙子……）</p>
<p>A&gt;B<br />
/*  匹配名为B且是A的孩子的元素：<br />
&lt;div&gt;Hello&lt;h1&gt;adblock, &lt;em&gt;I love you!&lt;/em&gt;&lt;/h1&gt;&lt;/div&gt;<br />
其中，h1是div的孩子，em是div的孙子……<br />
div&gt;h1：匹配<br />
div&gt;em：不匹配<br />
div em：匹配  */</p>
<p>A:first-child<br />
/*  匹配名为A且是其父母长子的元素<br />
&lt;h1&gt;&lt;strong&gt;Hello&lt;/strong&gt;&lt;em&gt;adblock!&lt;/em&gt;&lt;/h1&gt;<br />
其中，strong是长子，em不是<br />
strong:first-child：匹配<br />
em:first-child：不匹配  */</p>
<p>A + B<br />
/*  匹配名为B且是A<em>紧挨着的</em>弟弟的元素<br />
&lt;nl&gt;<br />
&lt;lable&gt;for many reasons:&lt;/lable&gt;<br />
&lt;li&gt;1&lt;/li&gt;<br />
&lt;li&gt;2&lt;/li&gt;<br />
&lt;li&gt;&#8230;&lt;/li&gt;<br />
&lt;/nl&gt;<br />
&lt;h1&gt;I love adblock&lt;/h1&gt;<br />
&lt;p&gt;and, I can&#8217;t help introducing it to you&lt;/p&gt;<br />
nl + h1：匹配<br />
h1 + p：匹配<br />
nl + p：不匹配  */</p>
<p>A[B]<br />
//  名为A且具有属性B的元素</p>
<p>A[B="C"]<br />
//  名为A且属性B<em>精确地</em>等于C的元素</p>
<p>A[B~="C"]<br />
/*  名为A且其属性B以空格分隔的多个值中的一个等于C的元素<br />
&lt;div class=”adv blink right_box”&gt;example&lt;/div&gt;<br />
div[class]：匹配<br />
div[class="adv blink right_box"]：匹配<br />
div[class~="blink"]：匹配<br />
div[class="blink"]：不匹配<br />
div.adv：匹配  */</p>
<p>A.B<br />
//等价于 A[class~="B"]</p>
<p>A#B<br />
//等价于 A[id="B"]</p>
<p>虽然看起来也不是很多，但将上面几种模式组合起来用，效果是很强大的。在实际的例子中，应该不会有隐藏不了的吧：）</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2007/06/adblock%e9%9a%90%e8%97%8f%e8%a7%84%e5%88%99%e4%b8%ad%e7%9a%84css%e9%80%89%e6%8b%a9%e5%99%a8/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sun建立Unix体验中心</title>
		<link>http://wangcongming.info/2007/05/sun%e5%bb%ba%e7%ab%8bunix%e4%bd%93%e9%aa%8c%e4%b8%ad%e5%bf%83/</link>
		<comments>http://wangcongming.info/2007/05/sun%e5%bb%ba%e7%ab%8bunix%e4%bd%93%e9%aa%8c%e4%b8%ad%e5%bf%83/#comments</comments>
		<pubDate>Sun, 06 May 2007 07:29:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[sftp]]></category>
		<category><![CDATA[SSH]]></category>
		<category><![CDATA[Sun]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[龙芯]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2007/05/06/sun%e5%bb%ba%e7%ab%8bunix%e4%bd%93%e9%aa%8c%e4%b8%ad%e5%bf%83/</guid>
		<description><![CDATA[如题，目前已有Solaris、Fedora、Debian，以及将有FreeBsd、Ubuntu系统供体验。一个简单的注册之后，通过SSH登录，普通用户权限。常见的包都打上了（自然也少不了他们自己的Sun Studio~），甚至有sftp（可以把本地开发的代码上传编译运行，或者将运行结果下载到本地）。开发语言方面，支持：C/C++、Fortran、Java、Ruby、Python、Perl、Lisp&#8230; 上去试了下，先打开vim编辑了个cpp，然后g++，一切正常～。不同的是，不像在自己的机器上，自己就是root，整台机器归自己所有。在那上面，无数终端连接共享一台服务器，很有点当年前辈们的感觉～～～。总之，对于暂时没有计算机，以及因为总总原因没有安装Unix系统的人来说，是一个不错的体验平台。 比较特别的是，它还能满足关于龙芯、多处理器、多核、多线程的兴趣和需求。]]></description>
			<content:encoded><![CDATA[<p>如题，目前已有Solaris、Fedora、Debian，以及将有FreeBsd、Ubuntu系统供体验。<a href="http://www.unix-center.net/uc/reg.php">一个简单的注册</a>之后，通过<a href="http://www.unix-center.net/?p=10">SSH登录</a>，普通用户权限。常见的包都打上了（自然也少不了他们自己的Sun Studio~），甚至有<a href="http://www.unix-center.net/?p=11">sftp</a>（可以把本地开发的代码上传编译运行，或者将运行结果下载到本地）。开发语言方面，支持：C/C++、Fortran、Java、Ruby、Python、Perl、Lisp&#8230;</p>
<p>上去试了下，先打开vim编辑了个cpp，然后g++，一切正常～。不同的是，不像在自己的机器上，自己就是root，整台机器归自己所有。在那上面，无数终端连接共享一台服务器，很有点当年前辈们的感觉～～～。总之，对于暂时没有计算机，以及因为总总原因没有安装Unix系统的人来说，是一个不错的体验平台。</p>
<p>比较特别的是，它还能满足关于<a href="http://www.unix-center.net/?p=34">龙芯</a>、多处理器、多核、多线程的兴趣和需求。</p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2007/05/sun%e5%bb%ba%e7%ab%8bunix%e4%bd%93%e9%aa%8c%e4%b8%ad%e5%bf%83/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter API 应用</title>
		<link>http://wangcongming.info/2007/04/twitter-api-%e5%ba%94%e7%94%a8/</link>
		<comments>http://wangcongming.info/2007/04/twitter-api-%e5%ba%94%e7%94%a8/#comments</comments>
		<pubDate>Sat, 28 Apr 2007 11:12:00 +0000</pubDate>
		<dc:creator>Wang Congming</dc:creator>
				<category><![CDATA[Geek Tweak]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://wangcongming.info/2007/04/28/twitter-api-%e5%ba%94%e7%94%a8/</guid>
		<description><![CDATA[题外话： &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 我的需求很简单，就是将最近的几条twitter信息显示在blog上。 首先想到的办法就是，直接用blogger提供的feed功能。可是，输出的每条信息前都有个“Wang Congming:”长长的前缀，不喜欢。而且，blogger每抓取一次feed好像要缓存挺长时间，而twitter应该是实效性比较强的，恩～。 然后，就想到用twitter官方提供的Badges。However，他们给的不是我想要的。所以，只好去看看API说明，自己动手。 小小原理： &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; twitter支持四种格式的数据输出：xml, RSS, ATOM, JSON，以及 GET 和 POST 两种方法。当然，只是查询一下不需要授权的数据，自然用不上POST。所以，只需要GET一个JSON就行，通过URL传递适当的参数，得到我们需要的数据。 传递过来的 json 是一个函数，而我们需要的数据作为函数的参数。唯一要做的，就是事先定义这样一个函数，告诉它该怎么执行，怎么显示其中的数据。至于函数名，GET 时由自己用 callback 参数指定。 Click the expand button to read full text&#8230; 数据结构 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 返回的数据类似以下结构： twitterCallback([ { "created_at":"Sat Apr 28 15:45:24 +0000 2007", "text":"信息的内容～", "id":43160262/*该条信息的数字编号*/, "user":{ "name":"Wang Congming", "profile_image_url":"http:...", "description":"自我介绍", "location":"BeiJing", "screen_name":"WCM/*用户名*/", "url":"http:...", "id":5002701/*用户的数字编号*/, "protected":false } }, [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight: bold;">题外话：</span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
我的需求很简单，就是将最近的几条twitter信息显示在blog上。</p>
<p>首先想到的办法就是，直接用blogger提供的feed功能。可是，输出的每条信息前都有个“Wang Congming:”长长的前缀，不喜欢。而且，blogger每抓取一次feed好像要缓存挺长时间，而twitter应该是实效性比较强的，恩～。</p>
<p>然后，就想到用twitter官方提供的Badges。However，他们给的不是我想要的。所以，只好去看看API说明，自己动手。</p>
<p><span style="font-weight: bold;">小小原理：</span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
twitter支持四种格式的数据输出：xml, RSS, ATOM, JSON，以及 GET 和 POST 两种方法。当然，只是查询一下不需要授权的数据，自然用不上POST。所以，只需要GET一个JSON就行，通过URL传递适当的参数，得到我们需要的数据。</p>
<p>传递过来的 json 是一个函数，而我们需要的数据作为函数的参数。唯一要做的，就是事先定义这样一个函数，告诉它该怎么执行，怎么显示其中的数据。至于函数名，GET 时由自己用 callback 参数指定。</p>
<p><span class="note_text">Click the expand button to read full text&#8230;</span></p>
<p><span style="font-weight: bold;">数据结构</span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
返回的数据类似以下结构：</p>
<pre>twitterCallback([   {      "created_at":"Sat Apr 28 15:45:24 +0000 2007",      "text":"信息的内容～",      "id":43160262/*该条信息的数字编号*/,      "user":{         "name":"Wang Congming",         "profile_image_url":"http:...",         "description":"自我介绍",         "location":"BeiJing",         "screen_name":"WCM/*用户名*/",         "url":"http:...",         "id":5002701/*用户的数字编号*/,         "protected":false      }   },   {      /* 第2/3/4...条信息，重复以上形式 */   }]);</pre>
<p><span style="font-weight: bold;">完成</span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
根据以上数据，得代码如下：</p>
<pre>&lt;ul id="my_twitter"&gt;&lt;li&gt;Loading...&lt;/li&gt;&lt;/ul&gt;

&lt;script type="text/javascript"&gt;function relative_time(time_value) {   var time_correct = time_value.split('+0000');   var parsed_date = Date.parse(time_correct[0]+'GMT+0000'+time_correct[1]);   var relative_to = new Date();   var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);   if(delta &lt; 60) return 'less than a minute ago';   else if(delta &lt; 120) return 'about a minute ago';   else if(delta &lt; (45*60)) return (parseInt(delta / 60)).toString() + ' minutes    ago';   else if(delta &lt; (90*60)) return 'about an hour ago';   else if(delta &lt; (24*60*60)) return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';   else if(delta &lt; (48*60*60)) return '1 day ago';   else return (parseInt(delta / 86400)).toString() + ' days ago';}function twitterCallback(obj){   var twitterHTML = '';   for(var i=0; i&lt;(obj.length); i++){      twitterHTML += '&lt;li&gt;&lt;span class="item-title"&gt;&lt;a href="http://twitter.com/wcm/statuses/'+obj[i].id+'"&gt;' + obj[i].text + '&lt;/a&gt;&lt;/span&gt;&lt;span class="item-date"&gt; - ' + relative_time(obj[i].created_at) + '&lt;/span&gt;&lt;/li&gt;';   }   document.getElementById('my_twitter').innerHTML = twitterHTML;}&lt;/script&gt;

&lt;script src="http://twitter.com/statuses/user_timeline/5002701.json?callback=twitterCallback&amp;count=5" type="text/javascript"&gt;&lt;/script&gt;</pre>
<p>效果如右侧～</p>
<p><span style="font-weight: bold;">总结一下</span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
1、以上代码，如果去掉ul间的“&lt;li&gt;Loading&#8230;&lt;/li&gt;”，然后存为一个单独的文件，将无法正常显示，加上后又变为正常。当然，并不限于Loading&#8230;，也并不限于ul之间。也就是说，只要在任何可以的地方，加上任何字符，就OK了，不加就不行，IE和ff均如此，不理解……。</p>
<p>2、twitter输出的”+0000&#8243;时区没有指名是哪个标准时间（虽然没多大差别），这将导致IE的Date.parse语法分析出错，所以先在”+0000&#8243;前加上GMT再分析。</p>
<p>3、”&#8230;/5002701.json?callback=twitterCallback&amp;count=5&#8243;。这里的5002701要换成自己的编号；twitterCallback即是指定的返回函数名，可自由命名；除了count外，还有其他筛选条件，如指定起始日期的since等。</p>
<p>4、<a href="http://groups.google.com/group/twitter-development-talk/web/api-documentation">Twitter API官方文档</a></p>
<p>关于JSON (JavaScript Object Notation): <a href="http://www.json.org/json-zh.html">http://www.json.org/json-zh.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://wangcongming.info/2007/04/twitter-api-%e5%ba%94%e7%94%a8/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

