<?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>Here comes the Sun &#187; 把戏</title>
	<atom:link href="http://sunng.info/blog/category/%e6%8a%8a%e6%88%8f/feed/" rel="self" type="application/rss+xml" />
	<link>http://sunng.info/blog</link>
	<description>Homemade Clojure Geek</description>
	<lastBuildDate>Fri, 11 May 2012 02:24:46 +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>Visualizing OpenStreetMap Nanjing Contribution</title>
		<link>http://sunng.info/blog/2012/04/visualizing-openstreetmap-nanjing-contribution/</link>
		<comments>http://sunng.info/blog/2012/04/visualizing-openstreetmap-nanjing-contribution/#comments</comments>
		<pubDate>Fri, 20 Apr 2012 07:02:40 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[Nanjing]]></category>
		<category><![CDATA[OpenStreetMap]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1221</guid>
		<description><![CDATA[早上在prismatic上看到mapbox的一篇博客，介绍通过TileMill可视化OSM的贡献者，非常酷。于是我在南京的地图上也做了一个这样的可视化。 一个详细的大图在这里。虽然只做了南京的五个主要贡献者，基本上涵盖了大部分数据。 图例就不专门输出了 [user = 'Sunng'] { marker-fill: @magenta;} [user = 'fuwuyuan'] { marker-fill: @blue;} [user = 'sinopitt'] {marker-fill: @yellow;} [user = 'larryy'] {marker-fill: @green;} [user = 'zhengz'] {marker-fill: @red;} MapBox家的东西真的非常酷，这家的技术以nodejs为主，围绕osm开发了不少产品。最近比较大的新闻，比如4sq转到osm上，其实就是转到这家的osm服务上。有兴趣你可以关注一下！]]></description>
			<content:encoded><![CDATA[<p>早上在prismatic上看到mapbox的一篇<a href="http://mapbox.com/blog/how-to-map-contributions-openstreetmap/" target="_blank">博客</a>，介绍通过TileMill可视化OSM的贡献者，非常酷。于是我在南京的地图上也做了一个这样的可视化。</p>
<p><img src="http://i.imgur.com/U2yXK.png" alt="" /></p>
<p>一个详细的大图在<a href="http://i.imgur.com/YnULm.png" target="_blank">这里</a>。虽然只做了南京的五个主要贡献者，基本上涵盖了大部分数据。</p>
<p>图例就不专门输出了<br />
[user = 'Sunng'] { marker-fill: @magenta;}<br />
[user = 'fuwuyuan'] { marker-fill: @blue;}<br />
[user = 'sinopitt'] {marker-fill: @yellow;}<br />
[user = 'larryy'] {marker-fill: @green;}<br />
[user = 'zhengz'] {marker-fill: @red;}</p>
<p>MapBox家的东西真的非常酷，这家的技术以nodejs为主，围绕osm开发了不少产品。最近比较大的新闻，比如4sq转到osm上，其实就是转到这家的osm服务上。有兴趣你可以关注一下！<br />
<img src="http://i.imgur.com/Hum2r.png" alt="" /></p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/04/visualizing-openstreetmap-nanjing-contribution/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>为WebWorker设置正确的路径</title>
		<link>http://sunng.info/blog/2012/03/%e4%b8%bawebworker%e8%ae%be%e7%bd%ae%e6%ad%a3%e7%a1%ae%e7%9a%84%e8%b7%af%e5%be%84/</link>
		<comments>http://sunng.info/blog/2012/03/%e4%b8%bawebworker%e8%ae%be%e7%bd%ae%e6%ad%a3%e7%a1%ae%e7%9a%84%e8%b7%af%e5%be%84/#comments</comments>
		<pubDate>Thu, 22 Mar 2012 09:32:32 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[heatcanvas]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1208</guid>
		<description><![CDATA[WebWorker的路径通常是写在代码源文件中，而且这个路径并非其相对父js文件的相对路径，而似乎是相对页面的路径。所以指定一个正确的可随处部署的路径变得有些麻烦。昨天有人给HeatCanvas提了这个问题我才想到上网搜索了一下，有一个还算挺不错的办法。 写一个getPath函数，从document里找到父js的路径，拼到Worker的名字上。对heatcanvas.js这个文件来说就是： HeatCanvas.getPath = function&#40;&#41; &#123; &#160; &#160; var scriptTags = document.getElementsByTagName&#40;&#34;script&#34;&#41;; &#160; &#160; for &#40;var i=0; i&#60;scriptTags.length; i++&#41; &#123; &#160; &#160; &#160; &#160; var src = scriptTags&#91;i&#93;.src; &#160; &#160; &#160; &#160; var pos = src.indexOf&#40;&#34;heatcanvas.js&#34;&#41;; &#160; &#160; &#160; &#160; &#8230; <a href="http://sunng.info/blog/2012/03/%e4%b8%bawebworker%e8%ae%be%e7%bd%ae%e6%ad%a3%e7%a1%ae%e7%9a%84%e8%b7%af%e5%be%84/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>WebWorker的路径通常是写在代码源文件中，而且这个路径并非其相对父js文件的相对路径，而似乎是相对页面的路径。所以指定一个正确的可随处部署的路径变得有些麻烦。昨天有人给HeatCanvas提了这个问题我才想到上网搜索了一下，有一个还算挺不错的办法。</p>
<p>写一个getPath函数，从document里找到父js的路径，拼到Worker的名字上。对heatcanvas.js这个文件来说就是：</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">HeatCanvas.<span style="color: #660066;">getPath</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> scriptTags <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementsByTagName</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;script&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span>scriptTags.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> src <span style="color: #339933;">=</span> scriptTags<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">src</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> pos <span style="color: #339933;">=</span> src.<span style="color: #660066;">indexOf</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;heatcanvas.js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>pos <span style="color: #339933;">&gt;</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> src.<span style="color: #660066;">substring</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> pos<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></div>
<p>因此现在HeatCanvas已经解决了这个路径问题，现在这个库应该更好用了。当然如果你改了我的文件名我就无话可说了。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/03/%e4%b8%bawebworker%e8%ae%be%e7%bd%ae%e6%ad%a3%e7%a1%ae%e7%9a%84%e8%b7%af%e5%be%84/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visualize Reddit upvotes by subreddit</title>
		<link>http://sunng.info/blog/2011/10/visualize-reddit-upvotes-by-subreddit/</link>
		<comments>http://sunng.info/blog/2011/10/visualize-reddit-upvotes-by-subreddit/#comments</comments>
		<pubDate>Thu, 27 Oct 2011 11:59:46 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[reddit]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1048</guid>
		<description><![CDATA[这是我reddit上所有的upvote在各个subreddit上的分布情况，这个情况还是可以说明我是个普通青年。 排在前几位的分别是 Programming Linux Python f7u12 Clojure Ubuntu 如果你还不了解什么是Reddit：Reddit是一个巨大的社会书签+论坛网站，他的频道叫做subreddit，每个频道有一个相应的主题，涵盖了从IT技术到新闻到生活的各个角落。 这些数据是通过下面的Clojure程序获得（使用reddit.clj库），并通过jfreechart展现出来的。]]></description>
			<content:encoded><![CDATA[<p>这是我reddit上所有的upvote在各个subreddit上的分布情况，这个情况还是可以说明我是个普通青年。<br />
<img src="http://i.imgur.com/jfXyK.png" alt="Reddit upvotes visualization" width="500px" /></p>
<p>排在前几位的分别是</p>
<ul>
<li>Programming</li>
<li>Linux</li>
<li>Python</li>
<li>f7u12</li>
<li>Clojure</li>
<li>Ubuntu</li>
</ul>
<p>如果你还不了解什么是Reddit：Reddit是一个巨大的社会书签+论坛网站，他的频道叫做subreddit，每个频道有一个相应的主题，涵盖了从IT技术到新闻到生活的各个角落。</p>
<p>这些数据是通过下面的Clojure程序获得（使用reddit.clj库），并通过jfreechart展现出来的。<br />
<script src="https://gist.github.com/1315572.js"> </script></p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/10/visualize-reddit-upvotes-by-subreddit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Substract a vector from a matrix in Octave</title>
		<link>http://sunng.info/blog/2011/10/substract-a-vector-from-a-matrix-in-octave/</link>
		<comments>http://sunng.info/blog/2011/10/substract-a-vector-from-a-matrix-in-octave/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 15:39:31 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[math]]></category>
		<category><![CDATA[octave]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1042</guid>
		<description><![CDATA[假设你有一个矩阵： A = [1,2;3,4;5,6] 以及一个矢量： B = [2,5] 你希望对A的每一行元素对元素地减B，例如第一行 [1-2,2-5] 但你不希望用循环完成这个工作，那么你可能想到利用B创建一个和A一样维度的矩阵然后进行.-： C = [2,5;2,5;2,5] A .- C 在Octave中可以利用repmat这个函数获得C： C = repmat(B, length(A), 1) 但是对于大矩阵来说这是一种对内存的浪费。 更好的方法是利用bsxfun： bsxfun(@minus, A, B) bsxfun在octave的文档中似乎鲜有提及。]]></description>
			<content:encoded><![CDATA[<p>假设你有一个矩阵：</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">A = [1,2;3,4;5,6]</div></div>
<p>以及一个矢量：</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">B = [2,5]</div></div>
<p>你希望对A的每一行元素对元素地减B，例如第一行</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[1-2,2-5]</div></div>
<p>但你不希望用循环完成这个工作，那么你可能想到利用B创建一个和A一样维度的矩阵然后进行.-：</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">C = [2,5;2,5;2,5]<br />
A .- C</div></div>
<p>在Octave中可以利用repmat这个函数获得C：</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">C = repmat(B, length(A), 1)</div></div>
<p>但是对于大矩阵来说这是一种对内存的浪费。</p>
<p>更好的方法是利用bsxfun：</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">bsxfun(@minus, A, B)</div></div>
<p>bsxfun在octave的文档中似乎鲜有提及。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/10/substract-a-vector-from-a-matrix-in-octave/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>手动设置Fedora15网卡</title>
		<link>http://sunng.info/blog/2011/05/%e6%89%8b%e5%8a%a8%e8%ae%be%e7%bd%aefedora15%e7%bd%91%e5%8d%a1/</link>
		<comments>http://sunng.info/blog/2011/05/%e6%89%8b%e5%8a%a8%e8%ae%be%e7%bd%aefedora15%e7%bd%91%e5%8d%a1/#comments</comments>
		<pubDate>Sat, 28 May 2011 07:16:29 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2011/05/%e6%89%8b%e5%8a%a8%e8%ae%be%e7%bd%aefedora15%e7%bd%91%e5%8d%a1/</guid>
		<description><![CDATA[今天上午的Fedora更新，版本为0.8.999.3的NetworkManager会致使NetworkManager和network service的版本不一致，从而导致网络功能无法使用。而这个时候要通过yum downgrade NetworkManager*降级又没有网络连接可用，悲剧。 这时只有手动设置网卡了。service network restart和 service NetworkManager restart都报告失败，ifconfig查看网卡，只有本地回环启动。 接下来接上网线，通过 ifconfig -a 查看所有的网卡接口，例如我的接口叫做em2. 启动网卡 ifconfig em2 up 查看网卡情况 ifconfig em2 如果没有获得ip，可以通过dhcpclient获得ip dhclient -4 em2 再查看网卡情况，如果获得了ip，可以尝试ping www.baidu.com，如果出现network unreachable的报错，需要再配置一下路由信息，其中gw是你的网关： route add default gw 192.168.1.1 这时你的网络应该暂时可用了，立刻执行yum downgrade NetworkManager*降级吧。]]></description>
			<content:encoded><![CDATA[<p>今天上午的Fedora更新，版本为<font face="monospace">0.8.999.3</font>的NetworkManager会致使NetworkManager和network service的版本不一致，从而导致网络功能无法使用。而这个时候要通过<font face="monospace">yum downgrade NetworkManager*</font>降级又没有网络连接可用，悲剧。</p>
<p>这时只有手动设置网卡了。<font face="monospace">service network restart</font>和 <font face="monospace">service NetworkManager restart</font>都报告失败，<font face="monospace">ifconfig</font>查看网卡，只有本地回环启动。</p>
<p>接下来接上网线，通过 <font face="monospace">ifconfig -a</font> 查看所有的网卡接口，例如我的接口叫做<font face="monospace">em2</font>.</p>
<p>启动网卡<br />
<font face="monospace">ifconfig em2 up</font></p>
<p>查看网卡情况<br />
<font face="monospace">ifconfig em2</font></p>
<p>如果没有获得ip，可以通过dhcpclient获得ip<br />
<font face="monospace">dhclient -4 em2</font></p>
<p>再查看网卡情况，如果获得了ip，可以尝试<font face="monospace">ping www.baidu.com</font>，如果出现network unreachable的报错，需要再配置一下路由信息，其中gw是你的网关：<br />
<font face="monospace">route add default gw 192.168.1.1</font></p>
<p>这时你的网络应该暂时可用了，立刻执行<font face="monospace">yum downgrade NetworkManager*</font>降级吧。</p>
<div class="zemanta-pixie"><img class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=551018aa-7e6c-81e6-b79a-bc1751d9b7be" /></div>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/05/%e6%89%8b%e5%8a%a8%e8%ae%be%e7%bd%aefedora15%e7%bd%91%e5%8d%a1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Correct source file encoding with one liner</title>
		<link>http://sunng.info/blog/2011/03/correct-source-file-encoding-with-one-liner/</link>
		<comments>http://sunng.info/blog/2011/03/correct-source-file-encoding-with-one-liner/#comments</comments>
		<pubDate>Tue, 08 Mar 2011 13:44:09 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2011/03/correct-source-file-encoding-with-one-liner/</guid>
		<description><![CDATA[Amoeba项目最早的代码可以追溯到2008年了，其中有多个作者贡献代码，因为一直在Windows下开发，所以没有使用UTF8编码，最近大家统一到UTF8，遇到了代码编码不正确的问题。 于是我们需要统一解决一下这个问题： iconv -f gbk -t utf8 -o ConnectionManager.java ConnectionManager.java 这样可以把gbk编码的源文件转换为UTF8，原地转换。 推广到整个代码目录，用find和xargs做，xargs通过-I来制定一个占位符。 find . -name &#34;*.java&#34; -type f -perm +600 -print &#124; xargs -I _ iconv -f gbk -t utf8 -o _ -c _ 结果发现iconv运行中报了错，进一步检查发现一部分代码正常转换了，另一部分却乱码了。原来，两个作者的代码分别是gbk和gb2312，这iconv转换的时候两种编码并不兼容。这就麻烦了，必须对代码分别处理才可以，区别代码的编码，暂时就用Java源文件里的作者名字。又看了一下find似乎没有对文件内容过滤的条件，不过不要紧，我们可以用xargs做： find . -name &#34;*.java&#34; -type &#8230; <a href="http://sunng.info/blog/2011/03/correct-source-file-encoding-with-one-liner/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://amoeba.meidusa.com/wordpress/">Amoeba</a>项目最早的代码可以追溯到2008年了，其中有多个作者贡献代码，因为一直在Windows下开发，所以没有使用UTF8编码，最近大家统一到UTF8，遇到了代码编码不正确的问题。</p>
<p>于是我们需要统一解决一下这个问题：</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">iconv -f gbk -t utf8 -o ConnectionManager.java ConnectionManager.java</div></div>
<p>这样可以把gbk编码的源文件转换为UTF8，原地转换。</p>
<p>推广到整个代码目录，用find和xargs做，xargs通过-I来制定一个占位符。</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">find . -name &quot;*.java&quot; -type f -perm +600 -print | xargs -I _ iconv -f gbk -t utf8 -o _ -c _</div></div>
<p>结果发现iconv运行中报了错，进一步检查发现一部分代码正常转换了，另一部分却乱码了。原来，两个作者的代码分别是gbk和gb2312，这iconv转换的时候两种编码并不兼容。这就麻烦了，必须对代码分别处理才可以，区别代码的编码，暂时就用Java源文件里的作者名字。又看了一下find似乎没有对文件内容过滤的条件，不过不要紧，我们可以用xargs做：</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">find . -name &quot;*.java&quot; -type f -perm +600 -print | xargs -I _ sh -c 'grep -q hexianmao _ &amp;&amp; iconv -f gb2312 -t utf8 -o _ -c _ '</div></div>
<p>对这位hexianmao作者的代码，我们利用grep进程的返回值来进行判断。grep的-q参数相当于>/dev/null。这里有一个tricky的地方，再xargs里我们不能直接用&#038;&#038;来组合命令，不过可以通过sh -c这样的方式，并且其中的占位符会被xargs合适地替换掉。</p>
<p>这样执行之后，这位作者的gb2312代码就被成功转换了。而另一部分作者的gbk代码也可以用同样方式解决了。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/03/correct-source-file-encoding-with-one-liner/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Fix ogg/oga not play in Firefox 3.6</title>
		<link>http://sunng.info/blog/2011/02/fix-oggoga-not-play-in-firefox-3-6/</link>
		<comments>http://sunng.info/blog/2011/02/fix-oggoga-not-play-in-firefox-3-6/#comments</comments>
		<pubDate>Tue, 15 Feb 2011 15:05:44 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[html]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2011/02/fix-oggoga-not-play-in-firefox-3-6/</guid>
		<description><![CDATA[Native audio support was introduced in since Firefox 3.5 . Ogg is one of the media format supported by Firefox. However, sometimes you may find it doesn&#8217;t work even if you set the right source path. And you just check &#8230; <a href="http://sunng.info/blog/2011/02/fix-oggoga-not-play-in-firefox-3-6/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Native audio support was introduced in since Firefox 3.5 . Ogg is one of the media format supported by Firefox. However, sometimes you may find it doesn&#8217;t work even if you set the right source path.  And you just check the network status of audio element:</p>
<p><i>document.getElementsByTagName(&#8220;audio&#8221;)[0].networkState</i></p>
<p>Then you get the constant of a 4, which is HTMLMediaElement.NETWORK_NO_SOURCE.</p>
<p>This is because firefox checks the Content-Type header to make sure it&#8217;s a media file. (Webkit based browsers don&#8217;t have this restriction.) However, ogg format is not configured on most http servers. You can check the content type by:<br />
<i>curl -I &lt;url-to-media-file&gt;</i></p>
<p>Take Apache as example, you can add following content to your configuration file:<br />
<i>AddType audio/ogg .oga</i><br />
<i>AddType video/ogg .ogv .ogg</i></p>
<p>For more, check this article:<br />
<a href="https://developer.mozilla.org/en/Configuring_servers_for_Ogg_media">https://developer.mozilla.org/en/Configuring_servers_for_Ogg_media</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/02/fix-oggoga-not-play-in-firefox-3-6/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The 4k Story</title>
		<link>http://sunng.info/blog/2010/10/the-4k-story/</link>
		<comments>http://sunng.info/blog/2010/10/the-4k-story/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 14:10:37 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mmap]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[redis]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/10/the-4k-story/</guid>
		<description><![CDATA[从 Redis 2.0 开始，Redis的作者就不断地被问道，你为什么要自己造一个VM轮子呢。尽管作者在FAQ里说明了，但是仍然有很多不同意见。 反向代理Varnish的开发人员，Poul-Henning Kamp 写了一篇文章，What&#8217;s wrong with 1975 programming ?，锋芒毕露，矛头直指竞争对手Squid，顺便也打击一大片牵连到了Redis的作者Antirez。他说： I have spent many years working on the FreeBSD kernel, and only rarely did I venture into userland programming, but when I had occation to do so, I &#8230; <a href="http://sunng.info/blog/2010/10/the-4k-story/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>从 Redis 2.0 开始，Redis的作者就不断地被问道，你为什么要自己造一个VM轮子呢。尽管作者在<a href="http://code.google.com/p/redis/wiki/FAQ#Do_you_plan_to_implement_Virtual_Memory_in_Redis?_Why_don%27t">FAQ</a>里说明了，但是仍然有很多不同意见。</p>
<p>反向代理Varnish的开发人员，Poul-Henning Kamp 写了一篇文章，<a href="http://www.varnish-cache.org/trac/wiki/ArchitectNotes">What&#8217;s wrong with 1975 programming ?</a>，锋芒毕露，矛头直指竞争对手Squid，顺便也打击一大片牵连到了Redis的作者Antirez。他说：</p>
<blockquote><p>I have spent many years working on the FreeBSD kernel, and only rarely did I venture into userland programming, but when I had occation to do so, I invariably found that people programmed like it was still 1975. </p></blockquote>
<p>Kamp兄有来到user-space之后一夜回到解放前的感觉，又好像摇晃着饮料瓶子对着Antirez说：你Out啦！也许是因为作者就是个内核开发者，所以Varnish对操作系统的Virtual Memory机制充分信任，把Squid对内存的手动管理称为wasted work。&#8221;So Welcome to Varnish, a 2006 architecture program. &#8221;</p>
<p>还有<a href="http://blog.kennejima.com/post/1226487020/thoughts-on-redis">用户</a>也提出</p>
<blockquote><p>
Redis doesn’t use OS swap. According to Salvatore Sanfilippo, the creator of Redis, it was because the page size of 4KB was too big. I personally don’t think that helps but it’d be better if Redis preallocated specified amount of buffer pool and bring related objects to the same page to increase locality of reference, instead of letting the heap manager blindly fragment objects. In my opinion, the page size of 32 bytes is too small, considering that the hardware architectures and the compilers are optimized for the conventional page size. In that scale, even the latency of reading something from RAM could be dominant (RAM is too slow for CPU, therefore it’s got L1/L2 cache), and RAM has the pipelined burst mode to pre-fetche memory contents at a few clock cycles, before they are actually requested.
</p></blockquote>
<p>5号，Antirez在博客上写了回击 <a href="http://antirez.com/post/what-is-wrong-with-2006-programming.html">What&#8217;s wrong with 2006 programming?</a>，他认为：</p>
<ul>
<li>OS Swap在一些情况下会导致客户端阻塞</li>
<li>4K大小的Page可能包含很多key，其中总有一些被访问到，导致操作系统无法swap这些page</li>
<li>使用自己实现的Paging为程序提供了极大的自由度，包括作者提到的2.2将会引入的数据压缩、新的数据结构以及自定义的过期算法</li>
</ul>
<p>前段时间，Foursquare用MongoDB时，因为Sharding方法一些疏漏把大量的数据集中到了一台机器上，导致一台EC2实例内存耗尽无法工作。Mongodb的内部机制就是mmap，我的同事做过相关的测试，当内存耗尽时，读写操作都使用磁盘，这时mongodb的性能是完全无法使用的。事后10gen的开发人员Horowitz总结出现问题的原因<a href="http://groups.google.com/group/mongodb-user/browse_thread/thread/528a94f287e9d77e">总结出现问题的原因</a>时，其中很重要的一点是</p>
<blockquote><p>Document size is less than 4k. Such documents, when moved, may be too small to free up pages and, thus, memory. </p></blockquote>
<p>看了这个原因，Redis的作者Twitter上大喜：&#8221;Real world instance of my 4k page + small objects concerns&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/10/the-4k-story/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Visualize call tree of a C function</title>
		<link>http://sunng.info/blog/2010/09/visualize-call-tree-of-a-c-function/</link>
		<comments>http://sunng.info/blog/2010/09/visualize-call-tree-of-a-c-function/#comments</comments>
		<pubDate>Fri, 24 Sep 2010 15:55:19 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[dot]]></category>
		<category><![CDATA[foss]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/09/visualize-call-tree-of-a-c-function/</guid>
		<description><![CDATA[Requirement You want to visualize a call hierarchy of a C function. Solution Utilities you need are listed below: GNU cflow cflow2vcg graphviz Take &#8216;rdbSaveBackground&#8217; (redis/rdb.c) for example: cflow --format=posix --omit-arguments --level-indent='0=\t' --level-indent='1=\t' --level-indent=start='\t' -m 'rdbSaveBackground' ~/osprojects/redis/src/rdb.c &#124; cflow2dot &#124; &#8230; <a href="http://sunng.info/blog/2010/09/visualize-call-tree-of-a-c-function/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h3>Requirement</h3>
<p>You want to visualize a call hierarchy of a C function.</p>
<h3>Solution</h3>
<p>Utilities you need are listed below:</p>
<ul>
<li><a href="http://www.gnu.org/software/cflow/">GNU cflow</a></li>
<li><a href="http://cflow2vcg.sourceforge.net/">cflow2vcg</a></li>
<li>graphviz</li>
</ul>
<p>Take &#8216;rdbSaveBackground&#8217; (<a href="http://github.com/antirez/redis/blob/master/src/rdb.c">redis/rdb.c</a>) for example:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">cflow <span style="color: #660033;">--format</span>=posix <span style="color: #660033;">--omit-arguments</span> <span style="color: #660033;">--level-indent</span>=<span style="color: #ff0000;">'0=\t'</span> <span style="color: #660033;">--level-indent</span>=<span style="color: #ff0000;">'1=\t'</span> <span style="color: #660033;">--level-indent</span>=<span style="color: #007800;">start</span>=<span style="color: #ff0000;">'\t'</span> <span style="color: #660033;">-m</span> <span style="color: #ff0000;">'rdbSaveBackground'</span> ~<span style="color: #000000; font-weight: bold;">/</span>osprojects<span style="color: #000000; font-weight: bold;">/</span>redis<span style="color: #000000; font-weight: bold;">/</span>src<span style="color: #000000; font-weight: bold;">/</span>rdb.c <span style="color: #000000; font-weight: bold;">|</span> cflow2dot <span style="color: #000000; font-weight: bold;">|</span> dot <span style="color: #660033;">-Tjpg</span> <span style="color: #660033;">-o</span> rdb.jpg</div></div>
<p>Output:<br />
<a href="http://www.flickr.com/photos/40741608@N08/5020142591/" title="visualization of a call tree by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4111/5020142591_7b34a52e3c.jpg" width="500" height="98" alt="visualization of a call tree" /></a></p>
<p>Source: <a href="http://unixdiary.blogspot.com/2006/05/using-cflow.html">unix diary</a></p>
<p>The post is brought to you by <a href="http://fedorahosted.org/lekhonee">lekhonee</a> v0.7</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/09/visualize-call-tree-of-a-c-function/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bayeux Protocol</title>
		<link>http://sunng.info/blog/2010/07/bayeux-protocol/</link>
		<comments>http://sunng.info/blog/2010/07/bayeux-protocol/#comments</comments>
		<pubDate>Sat, 17 Jul 2010 05:45:41 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[bayuex]]></category>
		<category><![CDATA[cometd]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[websocket]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/07/bayeux-protocol/</guid>
		<description><![CDATA[运行一个CometD Demo非常简单，只要创建一个Maven项目即可（CometD Howtos）： $ mvn archetype:generate -DarchetypeCatalog=http://cometd.org maven会提示用户选择archetype，包括cometd的版本1、版本2，jetty6、jetty7的实现，以及客户端dojo或jquery的实现。这里可以选择最新的： http://cometd.org -> cometd-archetype-dojo-jetty7 (2.0.0 &#8211; CometD archetype for creating a server-side event-driven web application) 项目创建完成后执行mvn jetty:run即可，打开http://127.0.0.1:8080/{artifactId}即可。 CometD的协议包容了各种主要的浏览器，比如在Chromium 5上，dojo采用WebSocket实现；而在不支持WebSocket的Firefox 3上，通过long-polling实现。Bayuex是一个应用协议，CometD是Bayuex的实现，类似鸡与蛋的关系。 有了昨天在Chromium上看WebSocket协议的经验，先看一下CometD的WebSocket实现： 握手。客户端请求/{artifactId}/cometd/handshake 包含Header GET /cometd-jetty/cometd/handshake HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: 127.0.0.1:8080 Origin: &#8230; <a href="http://sunng.info/blog/2010/07/bayeux-protocol/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>运行一个CometD Demo非常简单，只要创建一个Maven项目即可（<a href="http://cometd.org/documentation/howtos/primer">CometD Howtos</a>）：<br />
<i>$ mvn archetype:generate -DarchetypeCatalog=http://cometd.org</i></p>
<p>maven会提示用户选择archetype，包括cometd的版本1、版本2，jetty6、jetty7的实现，以及客户端dojo或jquery的实现。这里可以选择最新的：<br />
<i>http://cometd.org -> cometd-archetype-dojo-jetty7 (2.0.0 &#8211; CometD archetype for creating a server-side event-driven web application)</i></p>
<p>项目创建完成后执行mvn jetty:run即可，打开http://127.0.0.1:8080/{artifactId}即可。</p>
<p>CometD的协议包容了各种主要的浏览器，比如在Chromium 5上，dojo采用WebSocket实现；而在不支持WebSocket的Firefox 3上，通过long-polling实现。Bayuex是一个应用协议，CometD是Bayuex的实现，类似鸡与蛋的关系。</p>
<p>有了昨天在Chromium上看WebSocket协议的经验，先看一下CometD的WebSocket实现：<br />
握手。客户端请求/{artifactId}/cometd/handshake<br />
包含Header</p>
<blockquote><p>GET /cometd-jetty/cometd/handshake HTTP/1.1<br />
Upgrade: WebSocket<br />
Connection: Upgrade<br />
Host: 127.0.0.1:8080<br />
Origin: http://127.0.0.1:8080<br />
Cookie: JSESSIONID=12jqq6hbsfkfic8vzqpevxtrw
</p></blockquote>
<p>这是标准的WebSocket握手协议，服务端返回：</p>
<blockquote><p>HTTP/1.1 101 Web Socket Protocol Handshake<br />
Upgrade: WebSocket<br />
Connection: Upgrade<br />
WebSocket-Origin: http://127.0.0.1:8080<br />
WebSocket-Location: ws://127.0.0.1:8080/cometd-jetty/cometd/handshake</p></blockquote>
<p>双方完成WebSocket连接的建立。客户端通过websocket发送JSON，进行bayuex的握手：</p>
<blockquote><p>[{"version":"1.0","minimumVersion":"0.9","channel":"/meta/handshake","supportedConnectionTypes":["websocket","long-polling","callback-polling"],&#8221;advice&#8221;:{&#8220;timeout&#8221;:60000,&#8221;interval&#8221;:0},&#8221;id&#8221;:&#8221;1&#8243;}]</p></blockquote>
<p>服务端返回JSON，下发clientId完成握手：</p>
<blockquote><p>[{"channel":"/meta/handshake","clientId":"8g6dbnlqr2k6jfo1tdpaeb7iw","version":"1.0","successful":true,"minimumVersion":"1.0","id":"1","supportedConnectionTypes":["websocket","long-polling","callback-polling"]}]</p></blockquote>
<p>握手完成，bayuex连接建立。</p>
<p>在Demo中，客户端添加了一个handshake的listerner</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">function</span> _metaHandshake<span style="color: #009900;">&#40;</span>handshake<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>handshake.<span style="color: #660066;">successful</span> <span style="color: #339933;">===</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cometd.<span style="color: #660066;">batch</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cometd.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/hello'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>message<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dojo.<span style="color: #660066;">byId</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">innerHTML</span> <span style="color: #339933;">+=</span> <span style="color: #3366CC;">'&lt;div&gt;Server Says: '</span> <span style="color: #339933;">+</span> message.<span style="color: #660066;">data</span>.<span style="color: #660066;">greeting</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'&lt;/div&gt;'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #006600; font-style: italic;">// Publish on a service channel since the message is for the server only</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cometd.<span style="color: #660066;">publish</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/service/hello'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066;">name</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'World'</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span></div></div>
<p>所以在完成握手后，客户端发送一个批量请求，subscribe /hello频道，并且向/service/hello发送json格式的消息。向/service channel发送的信息<a href="http://svn.cometd.com/trunk/bayeux/bayeux.html#toc_81">表示客户端与服务端的单独通信</a>，不会被转发给其他客户端。<br />
id用于区分每个请求，<a href="http://svn.cometd.com/trunk/bayeux/bayeux.html#toc_38">bayuex spec规定</a>向/meta和/service发送的请求必须包含id字段，用于标示请求响应。<br />
请求的内容最终聚合为一个Json</p>
<blockquote><p>[{"channel":"/meta/subscribe","subscription":"/hello","id":"2","clientId":"8g6dbnlqr2k6jfo1tdpaeb7iw"},{"channel":"/service/hello","data":{"name":"World"},"id":"3","clientId":"8g6dbnlqr2k6jfo1tdpaeb7iw"}]</p></blockquote>
<p>服务端发回响应，id=2的请求成功，订阅/hello频道成功</p>
<blockquote><p>[{"channel":"/meta/subscribe","successful":true,"id":"2","subscription":"/hello"}]</p></blockquote>
<p>之后，服务端发回/hello channel的消息</p>
<blockquote><p>[{"channel":"/hello","data":{"greeting":"Hello, World"}},{"channel":"/service/hello","successful":true,"id":"3"}]</p></blockquote>
<p>客户端还要定期发送连接请求保持连接</p>
<blockquote><p>[{"channel":"/meta/connect","connectionType":"websocket","advice":{"timeout":0},"id":"4","clientId":"8g6dbnlqr2k6jfo1tdpaeb7iw"}]</p></blockquote>
<p>服务端返回，连接成功</p>
<blockquote><p>[{"channel":"/meta/connect","advice":{"reconnect":"retry","interval":2500,"timeout":15000},"successful":true,"id":"4"}]</p></blockquote>
<p>connect请求是用于在客户端和服务端维持连接， Bayeux标准中提到(<a href="http://svn.cometd.com/trunk/bayeux/bayeux.html#toc_52">1</a>, <a href="http://svn.cometd.com/trunk/bayeux/bayeux.html#toc_53">2</a>)：</p>
<blockquote><p>A transport MUST maintain one and only one outstanding connect message. When a HTTP response that contains a /meta/connect response terminates, the client MUST wait at least the interval specified in the last received advice before following the advice to reestablish the connection </p></blockquote>
<blockquote><p>
The client MUST maintain only a single outstanding connect message. If the server does not have a current outstanding connect and a connect is not received within a configured timeout, then the server SHOULD act as if a disconnect message has been received. </p></blockquote>
<p>至此，cometd客户端就可以在/hello频道上订阅、发布消息了。<br />
在Chromium上，所有的操作都在一个WebSocket连接上完成。</p>
<p>而当断开连接时，客户端向服务端发送</p>
<blockquote><p>[{"channel":"/meta/disconnect","id":"188","clientId":"a8iutjvfp7dtwhzrfujeonk5q"}]</p></blockquote>
<p>服务端响应</p>
<blockquote><p>[{"channel":"/meta/disconnect","successful":true,"id":"188"}]</p></blockquote>
<p>Bayuex基本上就可以理解为一个websocket上的应用协议了。</p>
<p>再看看Firefox 3.6上的实现。Firefox 3.6不支持WebSocket，所有的通信只能通过XHR来实现。<br />
握手，通过一个xhr post请求实现：</p>
<blockquote><p>POST /{artifactId}/cometd/handshake HTTP/1.1<br />
Host: 127.0.0.1:8080<br />
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6<br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br />
Accept-Language: en-us,en;q=0.5<br />
Accept-Encoding: gzip,deflate<br />
Accept-Charset: UTF-8,*<br />
Keep-Alive: 115<br />
Connection: keep-alive<br />
Content-Type: application/json;charset=UTF-8<br />
X-Requested-With: XMLHttpRequest<br />
Referer: http://127.0.0.1:8080/{artifactId}/<br />
Content-Length: 182<br />
Cookie: JSESSIONID=fjnyxb28raih1cnaljrijl1ic<br />
Pragma: no-cache<br />
Cache-Control: no-cache
</p></blockquote>
<p>服务器端响应：</p>
<blockquote><p>HTTP/1.1 200 OK<br />
Content-Type: application/json;charset=UTF-8<br />
Set-Cookie: BAYEUX_BROWSER=df92-h8q89f416mutgbpxrwb8185u;Path=/<br />
Content-Length: 213<br />
Server: Jetty(7.1.5.v20100705)</p>
<p>[{"channel":"/meta/handshake","clientId":"9185k23lo482oq1po3ivxup2cj","version":"1.0","successful":true,"minimumVersion":"1.0","id":"1","supportedConnectionTypes":["websocket","long-polling","callback-polling"]}]</p></blockquote>
<p>握手完成，执行客户端定义的回调。发送bayeux请求，通过一个新的XHR上<br />
[{"channel":"/meta/subscribe","subscription":"/hello","id":"2","clientId":"9185k23lo482oq1po3ivxup2cj"},{"channel":"/service/hello","data":{"name":"World"},"id":"3","clientId":"9185k23lo482oq1po3ivxup2cj"}]</p>
<p>服务端同时返回三个bayuex的请求响应</p>
<blockquote><p>[{"channel":"/meta/subscribe","successful":true,"id":"2","subscription":"/hello"},{"channel":"/hello","data":{"greeting":"Hello, World"}},{"channel":"/service/hello","successful":true,"id":"3"}]</p></blockquote>
<p>客户端开始发送连接请求</p>
<blockquote><p>[{"channel":"/meta/connect","connectionType":"long-polling","advice":{"timeout":0},"id":"4","clientId":"9185k23lo482oq1po3ivxup2cj"}]</p></blockquote>
<p>注意这里使用的是<a href="http://svn.cometd.com/trunk/bayeux/bayeux.html#toc_69">long-polling</a>方式，这是由dojo针对浏览器特性决定的。</p>
<blockquote><p>Long-polling server implementations attempt to hold open each request until there are events to deliver; the goal is to always have a pending request available to use for delivering events as they occur, thereby minimizing the latency in message delivery.</p></blockquote>
<p>如果没有新消息，服务端阻塞十秒后返回</p>
<blockquote><p>[{"channel":"/meta/connect","successful":true,"id":"7"}]</p></blockquote>
<p>客户端接收到返回立刻发起新的connect请求</p>
<p>当有新消息时，阻塞在服务器端的connect请求会立即返回，同时带回新的消息，如</p>
<blockquote><p>[{"channel":"/hello","data":{"name":"555"},"id":"6"},{"channel":"/meta/connect","successful":true,"id":"619"}]</p></blockquote>
<p>而如果是本客户端publish的新消息，会在请求成功的响应中返回，不会影响connect连接，如：</p>
<blockquote><p>[{"channel":"/hello","data":{"name":"nihao"},"id":"715"},{"channel":"/hello","successful":true,"id":"715"}]</p></blockquote>
<p>断开时，仍然是通过xhr post一条bayuex命令到服务端</p>
<blockquote><p>[{"channel":"/meta/disconnect","id":"750","clientId":"9185k23lo482oq1po3ivxup2cj"}]</p></blockquote>
<p>服务端响应：</p>
<blockquote><p>[{"channel":"/meta/disconnect","successful":true,"id":"750"}]</p></blockquote>
<p>至此，通过long polling方式实现bayuex的cometd客户端也描述清楚了。long-polling仍然是通过connect请求来实现pull的方式准实时，与websocket真正push的方式还是存在区别的。</p>
<p>The post is brought to you by <a href="http://fedorahosted.org/lekhonee">lekhonee</a> v0.7</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/07/bayeux-protocol/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

