<?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/"
	xmlns:georss="http://www.georss.org/georss">

<channel>
	<title>Here comes the Sun &#187; python</title>
	<atom:link href="http://sunng.info/blog/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://sunng.info/blog</link>
	<description>Life ramblings</description>
	<lastBuildDate>Thu, 02 Sep 2010 12:29:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>ls my python packages</title>
		<link>http://sunng.info/blog/2010/09/ls-my-python-packages/</link>
		<comments>http://sunng.info/blog/2010/09/ls-my-python-packages/#comments</comments>
		<pubDate>Thu, 02 Sep 2010 12:29:07 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[装备]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/09/ls-my-python-packages/</guid>
		<description><![CDATA[在豆瓣上看到一个无聊的秀gems的活动，我也无聊一下，秀一下eggs。 ls /usr/local/lib/python2.6/dist-packages/ &#124; grep .egg &#124; sed &#8216;s/\(.*\)/&#60;li&#62;\1&#60;\/li&#62;/&#8217; amqplib-0.6.1-py2.6.egg argparse-1.1-py2.6.egg-info AuthKit-0.4.5-py2.6.egg avro-1.3.3-py2.6.egg Beaker-1.3-py2.6.egg Beaker-1.5.4-py2.6.egg beanstalkc-0.2.0-py2.6.egg bottle-0.8.1-py2.6.egg bottle-0.8.3-py2.6.egg bpython-0.9.6.2-py2.6.egg bson-0.1.2-py2.6.egg CherryPy-3.1.2-py2.6.egg CouchDB-0.6-py2.6.egg coverage-3.2-py2.6-linux-i686.egg Cython-0.12.1-py2.6-linux-i686.egg decorator-3.0.0-py2.6.egg distribute-0.6.14-py2.6.egg Django-1.0.2_final-py2.6.egg Django-1.1-py2.6.egg Django-1.2-py2.6.egg django_sphinx-2.2.3-py2.6.egg docutils-0.6-py2.6.egg Editra-0.4.95-py2.6.egg Editra-0.5.05-py2.6.egg Editra-0.5.72-py2.6.egg elementtree-1.2.7_20070827_preview-py2.6.egg eventlet-0.9.9-py2.6.egg Fabric-0.9.1-py2.6.egg fapws3-0.5.dev-py2.6-linux-i686.egg FormEncode-1.2.1-py2.6.egg GeoAlchemy-0.1-py2.6.egg Geohash-1.0rc1-py2.6.egg gevent-0.13.0.egg-info greenlet-0.3.1-py2.6-linux-i686.egg gunicorn-0.10.0-py2.6.egg gunicorn-0.11.0-py2.6.egg gunicorn-0.8.1-py2.6.egg httplib2-0.5.0-py2.6.egg ipython-0.10-py2.6.egg ipython-0.9.1-py2.6.egg Jinja2-2.5-py2.6.egg Mako-0.2.4-py2.6.egg Mako-0.3.4-py2.6.egg Markdoc-0.6.4-py2.6.egg-info Markdown-2.0.3-py2.6.egg Markdown-2.0.3-py2.6.egg-info [...]]]></description>
			<content:encoded><![CDATA[<p>在豆瓣上看到一个无聊的<a href="http://www.douban.com/online/10544092/">秀gems的活动</a>，我也无聊一下，秀一下eggs。</p>
<p><i>ls /usr/local/lib/python2.6/dist-packages/ | grep .egg | sed &#8216;s/\(.*\)/&lt;li&gt;\1&lt;\/li&gt;/&#8217;</i></p>
<ul>
<li>amqplib-0.6.1-py2.6.egg</li>
<li>argparse-1.1-py2.6.egg-info</li>
<li>AuthKit-0.4.5-py2.6.egg</li>
<li>avro-1.3.3-py2.6.egg</li>
<li>Beaker-1.3-py2.6.egg</li>
<li>Beaker-1.5.4-py2.6.egg</li>
<li>beanstalkc-0.2.0-py2.6.egg</li>
<li>bottle-0.8.1-py2.6.egg</li>
<li>bottle-0.8.3-py2.6.egg</li>
<li>bpython-0.9.6.2-py2.6.egg</li>
<li>bson-0.1.2-py2.6.egg</li>
<li>CherryPy-3.1.2-py2.6.egg</li>
<li>CouchDB-0.6-py2.6.egg</li>
<li>coverage-3.2-py2.6-linux-i686.egg</li>
<li>Cython-0.12.1-py2.6-linux-i686.egg</li>
<li>decorator-3.0.0-py2.6.egg</li>
<li>distribute-0.6.14-py2.6.egg</li>
<li>Django-1.0.2_final-py2.6.egg</li>
<li>Django-1.1-py2.6.egg</li>
<li>Django-1.2-py2.6.egg</li>
<li>django_sphinx-2.2.3-py2.6.egg</li>
<li>docutils-0.6-py2.6.egg</li>
<li>Editra-0.4.95-py2.6.egg</li>
<li>Editra-0.5.05-py2.6.egg</li>
<li>Editra-0.5.72-py2.6.egg</li>
<li>elementtree-1.2.7_20070827_preview-py2.6.egg</li>
<li>eventlet-0.9.9-py2.6.egg</li>
<li>Fabric-0.9.1-py2.6.egg</li>
<li>fapws3-0.5.dev-py2.6-linux-i686.egg</li>
<li>FormEncode-1.2.1-py2.6.egg</li>
<li>GeoAlchemy-0.1-py2.6.egg</li>
<li>Geohash-1.0rc1-py2.6.egg</li>
<li>gevent-0.13.0.egg-info</li>
<li>greenlet-0.3.1-py2.6-linux-i686.egg</li>
<li>gunicorn-0.10.0-py2.6.egg</li>
<li>gunicorn-0.11.0-py2.6.egg</li>
<li>gunicorn-0.8.1-py2.6.egg</li>
<li>httplib2-0.5.0-py2.6.egg</li>
<li>ipython-0.10-py2.6.egg</li>
<li>ipython-0.9.1-py2.6.egg</li>
<li>Jinja2-2.5-py2.6.egg</li>
<li>Mako-0.2.4-py2.6.egg</li>
<li>Mako-0.3.4-py2.6.egg</li>
<li>Markdoc-0.6.4-py2.6.egg-info</li>
<li>Markdown-2.0.3-py2.6.egg</li>
<li>Markdown-2.0.3-py2.6.egg-info</li>
<li>MarkupSafe-0.9.2-py2.6-linux-i686.egg</li>
<li>meinheld-0.3.1-py2.6-linux-i686.egg</li>
<li>Ming-0.2-py2.6.egg</li>
<li>mock-0.6.0-py2.6.egg</li>
<li>mocker-0.10.1-py2.6.egg</li>
<li>MySQL_python-1.2.3c1-py2.6-linux-i686.egg</li>
<li>networkx-1.0rc1-py2.6.egg</li>
<li>nose-0.10.4-py2.6.egg</li>
<li>numpy-1.4.1-py2.6-linux-i686.egg</li>
<li>Paste-1.7.2-py2.6.egg</li>
<li>PasteDeploy-1.3.3-py2.6.egg</li>
<li>PasteScript-1.7.3-py2.6.egg</li>
<li>pip-0.4-py2.6.egg</li>
<li>pip-0.8-py2.6.egg</li>
<li>progressbar-2.2-py2.6.egg</li>
<li>psycopg2-2.2.2-py2.6-linux-i686.egg</li>
<li>pycurl-7.19.0-py2.6-linux-i686.egg</li>
<li>pyev-0.5.3_3.8-py2.6-linux-i686.egg</li>
<li>Pygments-1.0-py2.6.egg</li>
<li>Pygments-1.3.1-py2.6.egg</li>
<li>pygooglechart-0.2.1-py2.6.egg</li>
<li>PyGreSQL-4.0-py2.6-linux-i686.egg</li>
<li>Pylons-0.9.7-py2.6.egg</li>
<li>Pylons-1.0-py2.6.egg</li>
<li>pymongo-1.6-py2.6-linux-i686.egg</li>
<li>pymongo-1.7-py2.6-linux-i686.egg</li>
<li>pymongo-1.8-py2.6-linux-i686.egg</li>
<li>pysal-1.0.0.egg-info</li>
<li>python_cjson-1.0.5-py2.6-linux-i686.egg</li>
<li>python_memcached-1.45-py2.6.egg</li>
<li>python_openid-2.2.5-py2.6.egg</li>
<li>PyXML-0.8.4-py2.6-linux-i686.egg</li>
<li>PyYAML-3.09-py2.6.egg-info</li>
<li>RDFobject-0.1.4-py2.6.egg</li>
<li>Rocket-1.1.1-py2.6.egg</li>
<li>Routes-1.10.3-py2.6.egg</li>
<li>Routes-1.12.3-py2.6.egg</li>
<li>Rtree-0.6.0-py2.6.egg</li>
<li>ruffus-2.2-py2.6.egg</li>
<li>scipy-0.8.0-py2.6-linux-i686.egg</li>
<li>setuptools-0.6c11-py2.6.egg-info</li>
<li>setuptools-0.6c9-py2.6.egg</li>
<li>setuptools-0.6c9-py2.6.egg.OLD.1283177768.67</li>
<li>Shapely-1.0.12-py2.6.egg</li>
<li>Shapely-1.2-py2.6.egg</li>
<li>simplejson-2.0.8-py2.6.egg</li>
<li>Spawning-0.9.3rc2-py2.6.egg</li>
<li>Sphinx-1.0b2-py2.6.egg</li>
<li>SQLAlchemy-0.6.3-py2.6.egg</li>
<li>Tempita-0.2-py2.6.egg</li>
<li>threadpool-1.2.7-py2.6.egg</li>
<li>tornado-0.2-py2.6.egg</li>
<li>twill-0.9-py2.6.egg</li>
<li>Twisted-10.1.0-py2.6-linux-i686.egg</li>
<li>vimpdb-0.3.8-py2.6.egg</li>
<li>virtualenv-1.3.3-py2.6.egg</li>
<li>WebError-0.10.1-py2.6.egg</li>
<li>WebHelpers-0.6.4-py2.6.egg</li>
<li>WebOb-0.9.6.1-py2.6.egg</li>
<li>web.py-0.32-py2.6.egg-info</li>
<li>web.py-0.34-py2.6.egg</li>
<li>WebTest-1.1-py2.6.egg</li>
<li>Werkzeug-0.6.2-py2.6.egg</li>
<li>whizzer-0.2.egg-info</li>
</ul>
<p>话说用sed能不能让开头重复的行不输出呢？或者什么命令能实现？</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/ls-my-python-packages/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>sunng&#8217;s pastebin</title>
		<link>http://sunng.info/blog/2010/07/sunngs-pastebin/</link>
		<comments>http://sunng.info/blog/2010/07/sunngs-pastebin/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 14:12:03 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[广告]]></category>
		<category><![CDATA[gae]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=639</guid>
		<description><![CDATA[写了一个基本的pastebin放在appengine上： http://sunoffline.appspot.com/pb/ 支持纯文本、Markdown和代码高亮。数据永久保留，推荐大家收藏以备不时之需。 The post is brought to you by lekhonee v0.7]]></description>
			<content:encoded><![CDATA[<p>写了一个基本的pastebin放在appengine上：<br />
<a href="http://sunoffline.appspot.com/pb/">http://sunoffline.appspot.com/pb/</a></p>
<p>支持纯文本、Markdown和代码高亮。数据永久保留，推荐大家收藏以备不时之需。</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/sunngs-pastebin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>bottle &amp; fapws3</title>
		<link>http://sunng.info/blog/2010/07/bottle-fapws3/</link>
		<comments>http://sunng.info/blog/2010/07/bottle-fapws3/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 13:37:34 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[装备]]></category>
		<category><![CDATA[bottle]]></category>
		<category><![CDATA[fapws3]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[wsgi]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/07/bottle-fapws3/</guid>
		<description><![CDATA[Bottle是一个Python web框架，兼容wsgi标准，lightweight，self-contained。 提到web框架，自然要和相类似的python框架相比。 Django是大型框架，包含ORM、Controller、Templating全套，这也是Django的缺点，使用Django意味着必须使用关系型数据库进行存储（尽管有一些Model层的其他实现，但绝大多数都是Hack的方式实现），必须使用Django并不非常出色的Template系统。Pylons针对Django的这些问题，采用了松散的方式，数据层可选择由SQLAlchemy实现，模板系统可以选择mako / jinja等。Pylons用paster来管理项目、创建代码模板。借鉴了rails的哲学，目录结构也相类似。可是pylons仍然显得重量级，把注意力放到web.py。只要定义一个router，定义相应的handler就可以处理web请求，handler对象的GET POST等方法分别对应相应的HTTP请求。看起来不错了，不过与bottle相比，webpy仍然显得繁琐、功能有限，而且它本身的db模块就更加鸡肋了。 看一个实例便知： 定义一个简单的HTTP页面： from bottle import Bottle, run, mako_view, request from bottle import FapwsServer myapp = Bottle&#40;&#41; @myapp.route&#40;'/nihao/:name/:count#\\d+#'&#41; @mako_view&#40;'nihao'&#41; def nihao&#40;name, count&#41;: &#160; &#160; return dict&#40;n=name, c=int&#40;count&#41;, ip=request.environ.get&#40;'REMOTE_ADDR'&#41;&#41; run&#40;app=myapp, server=FapwsServer&#41; 对应的nihao.tpl模板，用mako引擎实现： &#60;html&#62; &#60;head&#62; &#160; &#160; &#60;meta http-equiv=&#34;content-type&#34; content=&#34;text/html; charset=utf-8&#34;&#62; &#160; &#160; &#60;title&#62;Nihao&#60;/title&#62; &#60;/head&#62; &#60;body&#62; &#160; &#160; &#60;div id=&#34;ip&#34;&#62; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/defnull/bottle">Bottle</a>是一个Python web框架，兼容<a href="http://www.python.org/dev/peps/pep-0333">wsgi</a>标准，lightweight，self-contained。</p>
<p>提到web框架，自然要和相类似的python框架相比。</p>
<p>Django是大型框架，包含ORM、Controller、Templating全套，这也是Django的缺点，使用Django意味着必须使用关系型数据库进行存储（尽管有一些Model层的其他实现，但绝大多数都是Hack的方式实现），必须使用Django并不非常出色的Template系统。Pylons针对Django的这些问题，采用了松散的方式，数据层可选择由SQLAlchemy实现，模板系统可以选择mako / jinja等。Pylons用paster来管理项目、创建代码模板。借鉴了rails的哲学，目录结构也相类似。可是pylons仍然显得重量级，把注意力放到web.py。只要定义一个router，定义相应的handler就可以处理web请求，handler对象的GET POST等方法分别对应相应的HTTP请求。看起来不错了，不过与bottle相比，webpy仍然显得繁琐、功能有限，而且它本身的db模块就更加鸡肋了。</p>
<p>看一个实例便知：<br />
定义一个简单的HTTP页面：</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> Bottle, run, mako_view, request<br />
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> FapwsServer<br />
<br />
myapp = Bottle<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
@myapp.<span style="color: black;">route</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/nihao/:name/:count#<span style="color: #000099; font-weight: bold;">\\</span>d+#'</span><span style="color: black;">&#41;</span><br />
@mako_view<span style="color: black;">&#40;</span><span style="color: #483d8b;">'nihao'</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> nihao<span style="color: black;">&#40;</span>name, count<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>n=name, c=<span style="color: #008000;">int</span><span style="color: black;">&#40;</span>count<span style="color: black;">&#41;</span>, ip=request.<span style="color: black;">environ</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'REMOTE_ADDR'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
<br />
run<span style="color: black;">&#40;</span>app=myapp, server=FapwsServer<span style="color: black;">&#41;</span></div></div>
<p>对应的nihao.tpl模板，用mako引擎实现：</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/html.html"><span style="color: #000000; font-weight: bold;">html</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/head.html"><span style="color: #000000; font-weight: bold;">head</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/meta.html"><span style="color: #000000; font-weight: bold;">meta</span></a> <span style="color: #000066;">http-equiv</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;content-type&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/html; charset=utf-8&quot;</span>&gt;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/title.html"><span style="color: #000000; font-weight: bold;">title</span></a>&gt;</span>Nihao<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/title.html"><span style="color: #000000; font-weight: bold;">title</span></a>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/head.html"><span style="color: #000000; font-weight: bold;">head</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/body.html"><span style="color: #000000; font-weight: bold;">body</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;ip&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/h1.html"><span style="color: #000000; font-weight: bold;">h1</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;heading&quot;</span>&gt;</span>Request From ${ip}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/h1.html"><span style="color: #000000; font-weight: bold;">h1</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;%def <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;greeting(n)&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;name&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Nihao ${n}<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>%def&gt;</span><br />
&nbsp; &nbsp; % for i in range(c):<br />
&nbsp; &nbsp; &nbsp; &nbsp; ${greeting(n)}<br />
&nbsp; &nbsp; % endfor<br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/body.html"><span style="color: #000000; font-weight: bold;">body</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/html.html"><span style="color: #000000; font-weight: bold;">html</span></a>&gt;</span></div></div>
<p>仅仅是一些简单的内容，接着只需要：<br />
<i>python bottle-test.py</i><br />
即可运行服务器。</p>
<p>bottle通过decorator定义route规则，还支持url提取参数。通过decorator指定模板、模板引擎。可以说近乎简化到了极致。</p>
<p>bottle遵循单一职责原则，不提供数据层的实现，由用户自己指定，bottle没有任何限制。模板引擎，bottle支持mako / jinja / cheetah，本身还内建一个默认SimpleTemplate引擎。bottle还支持多种wsgi服务器，包括flup / wsgiref / cherrypy / paste / twisted / tornado / fapws3 等等。</p>
<p>最后提一个wsgi的实现<a href="http://github.com/william-os4y/fapws3">fapws3</a>，号称是目前最快的wsgi服务器。fapws3用libev实现，在不同的操作系统上采用不同的多路IO模型以达到高性能。</p>
<p>bottle的作者做过一个关于不同实现的性能比较：<br />
<a href="http://bottle.paws.de/page/2009-12-19_Comparing_HelloWorld_Performance">http://bottle.paws.de/page/2009-12-19_Comparing_HelloWorld_Performance</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/07/bottle-fapws3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Exaile-doubanfm-plugin 0.0.2</title>
		<link>http://sunng.info/blog/2010/07/exaile-doubanfm-plugin-0-0-2/</link>
		<comments>http://sunng.info/blog/2010/07/exaile-doubanfm-plugin-0-0-2/#comments</comments>
		<pubDate>Sun, 04 Jul 2010 14:17:53 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[广告]]></category>
		<category><![CDATA[Douban]]></category>
		<category><![CDATA[exaile]]></category>
		<category><![CDATA[foss]]></category>
		<category><![CDATA[gtk]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/07/exaile-doubanfm-plugin-0-0-2/</guid>
		<description><![CDATA[Exaile doubanfm plugin 0.0.2 预览版，目标是在Linux桌面提供豆瓣电台的完整体验。 目前插件只能运行在Exaile 0.3.1版本上。 0.0.2增加了豆瓣电台专用的视图： 相比第一版通过rating来实现豆瓣电台喜欢、跳过和删除的功能，在专用视图上有专门的按钮来操作。 其他细节更新： 当剩余曲目超过15首时不再增加播放列表 当播放到最后一首歌曲取新播放列表时增加重试机制 修正libdbfm跳过曲目bug一个 安装： 打开Exaile Preference，Plugin页，点击按钮Install Plugin，选择doubanfm.exz即可。如果存在问题，可以执行以下命令： mv doubanfm.exz douban.tar.gz tar xf doubanfm.tar.gz mv doubanfm ~/.local/share/exaile/plugins/ 转到doubanfm设置页面，填写用户名密码重启Exaile。 打开File菜单，选择豆瓣电台频道 选择曲目就可以开始播放了，选择视图中豆瓣电台视图可以切换到豆瓣电台视图。 项目地址： http://github.com/sunng87/exaile-doubanfm-plugin 下载： http://github.com/sunng87/exaile-doubanfm-plugin/downloads 另外，doubancovers插件也有一个针对豆瓣电台的更新可以快速获取豆瓣电台音乐的封面： http://bitbucket.org/sunng/exailedoubancovers/downloads?highlight=9265 The post is brought to you by lekhonee v0.7]]></description>
			<content:encoded><![CDATA[<p>Exaile doubanfm plugin 0.0.2 预览版，目标是在Linux桌面提供豆瓣电台的完整体验。</p>
<p><strong>目前插件只能运行在Exaile 0.3.1版本上。</strong></p>
<p>0.0.2增加了豆瓣电台专用的视图：<br />
<a href="http://www.flickr.com/photos/40741608@N08/4760493886/" title="screenshot_001 by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4075/4760493886_5e334726cf.jpg" width="408" height="156" alt="screenshot_001" /></a></p>
<p>相比第一版通过rating来实现豆瓣电台喜欢、跳过和删除的功能，在专用视图上有专门的按钮来操作。</p>
<p>其他细节更新：</p>
<ul>
<li>当剩余曲目超过15首时不再增加播放列表</li>
<li>当播放到最后一首歌曲取新播放列表时增加重试机制</li>
<li>修正libdbfm跳过曲目bug一个</li>
</ul>
<p>安装：<br />
打开Exaile Preference，Plugin页，点击按钮Install Plugin，选择doubanfm.exz即可。如果存在问题，可以执行以下命令：<br />
mv doubanfm.exz douban.tar.gz<br />
tar xf doubanfm.tar.gz<br />
mv doubanfm ~/.local/share/exaile/plugins/</p>
<p>转到doubanfm设置页面，填写用户名密码重启Exaile。<br />
<a href="http://www.flickr.com/photos/40741608@N08/4754666940/" title="screenshot_002 by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4141/4754666940_b998d99c4b.jpg" width="500" height="412" alt="screenshot_002" /></a></p>
<p>打开File菜单，选择豆瓣电台频道<br />
<a href="http://www.flickr.com/photos/40741608@N08/4754619030/" title="screenshot_001 by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4094/4754619030_933e00fcfa.jpg" width="500" height="359" alt="screenshot_001" /></a></p>
<p>选择曲目就可以开始播放了，选择视图中豆瓣电台视图可以切换到豆瓣电台视图。</p>
<p>项目地址：<br />
<a href="http://github.com/sunng87/exaile-doubanfm-plugin">http://github.com/sunng87/exaile-doubanfm-plugin</a></p>
<p>下载：<br />
<a href="http://github.com/sunng87/exaile-doubanfm-plugin/downloads">http://github.com/sunng87/exaile-doubanfm-plugin/downloads</a></p>
<p>另外，doubancovers插件也有一个针对豆瓣电台的更新可以快速获取豆瓣电台音乐的封面：<br />
<a href="http://bitbucket.org/sunng/exailedoubancovers/downloads?highlight=9265">http://bitbucket.org/sunng/exailedoubancovers/downloads?highlight=9265</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/07/exaile-doubanfm-plugin-0-0-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>exaile豆瓣电台插件(exaile-doubanfm-plugin)</title>
		<link>http://sunng.info/blog/2010/07/exaile%e8%b1%86%e7%93%a3%e7%94%b5%e5%8f%b0%e6%8f%92%e4%bb%b6exaile-doubanfm-plugin/</link>
		<comments>http://sunng.info/blog/2010/07/exaile%e8%b1%86%e7%93%a3%e7%94%b5%e5%8f%b0%e6%8f%92%e4%bb%b6exaile-doubanfm-plugin/#comments</comments>
		<pubDate>Fri, 02 Jul 2010 10:07:04 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[广告]]></category>
		<category><![CDATA[Douban]]></category>
		<category><![CDATA[exaile]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/07/exaile%e8%b1%86%e7%93%a3%e7%94%b5%e5%8f%b0%e6%8f%92%e4%bb%b6exaile-doubanfm-plugin/</guid>
		<description><![CDATA[豆瓣电台一直是flash客户端，嵌入浏览器，出于对flash的厌恶，本人开发了这个exaile插件，让广大linux同学在exaile里享受豆瓣电台一目了然桌面集成和全部豆瓣电台功能。 exaile-doubanfm-plugin features: 登录豆瓣，获取豆瓣电台播放列表 持续下载电台播放列表，实现不重复的持续播放 标记/取消“喜爱”、标记“回收站”、跳过 显示歌曲信息 项目地址： http://github.com/sunng87/exaile-doubanfm-plugin 下载页： http://github.com/sunng87/exaile-doubanfm-plugin/downloads 使用： 激活插件，填写用户名密码 重启exaile 文件菜单，open douban.fm，选择频道 点击播放开始 将rating设置为5 标记喜欢 rating设置2 豆瓣标准跳过 rating设置1 豆瓣删除 The post is brought to you by lekhonee v0.7]]></description>
			<content:encoded><![CDATA[<p>豆瓣电台一直是flash客户端，嵌入浏览器，出于对flash的厌恶，本人开发了这个exaile插件，让广大linux同学在exaile里享受豆瓣电台一目了然桌面集成和全部豆瓣电台功能。</p>
<p>exaile-doubanfm-plugin features:</p>
<ul>
<li>登录豆瓣，获取豆瓣电台播放列表</li>
<li>持续下载电台播放列表，实现不重复的持续播放</li>
<li>标记/取消“喜爱”、标记“回收站”、跳过</li>
<li>显示歌曲信息</li>
</ul>
<p><a href="http://www.flickr.com/photos/40741608@N08/4754619030/" title="screenshot_001 by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4094/4754619030_933e00fcfa.jpg" width="500" height="359" alt="screenshot_001" /></a></p>
<p><a href="http://www.flickr.com/photos/40741608@N08/4754615592/" title="screenshot_002 by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4079/4754615592_0c1486c2df.jpg" width="500" height="359" alt="screenshot_002" /></a></p>
<p><a href="http://www.flickr.com/photos/40741608@N08/4754666940/" title="screenshot_002 by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4141/4754666940_b998d99c4b.jpg" width="500" height="412" alt="screenshot_002" /></a></p>
<p>项目地址：<br />
<a href="http://github.com/sunng87/exaile-doubanfm-plugin">http://github.com/sunng87/exaile-doubanfm-plugin</a></p>
<p>下载页：<br />
<a href="http://github.com/sunng87/exaile-doubanfm-plugin/downloads">http://github.com/sunng87/exaile-doubanfm-plugin/downloads</a></p>
<p>使用：</p>
<ol>
<li>激活插件，填写用户名密码</li>
<li>重启exaile</li>
<li>文件菜单，open douban.fm，选择频道</li>
<li>点击播放开始</li>
<li>将rating设置为5 标记喜欢</li>
<li>rating设置2 豆瓣标准跳过</li>
<li>rating设置1 豆瓣删除</li>
</ol>
<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/exaile%e8%b1%86%e7%93%a3%e7%94%b5%e5%8f%b0%e6%8f%92%e4%bb%b6exaile-doubanfm-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python获取本机IP</title>
		<link>http://sunng.info/blog/2010/06/python%e8%8e%b7%e5%8f%96%e6%9c%ac%e6%9c%baip/</link>
		<comments>http://sunng.info/blog/2010/06/python%e8%8e%b7%e5%8f%96%e6%9c%ac%e6%9c%baip/#comments</comments>
		<pubDate>Sat, 05 Jun 2010 14:38:01 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=581</guid>
		<description><![CDATA[除了用inetface库和分析ifconfig输出以外，一个比较简单的获取本机IP的方法： import socket def get_local_ip&#40;&#41;: &#160; &#160; s = socket.socket&#40;socket.AF_INET, socket.SOCK_DGRAM&#41; &#160; &#160; s.connect&#40;&#40;&#34;sdo.com&#34;,80&#41;&#41; &#160; &#160; return s.getsockname&#40;&#41;&#91;0&#93; 参考 http://stackoverflow.com/questions/166506/finding-local-ip-addresses-in-python]]></description>
			<content:encoded><![CDATA[<p>除了用<a href="http://alastairs-place.net/netifaces/">inetface</a>库和分析ifconfig输出以外，一个比较简单的获取本机IP的方法：</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">socket</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> get_local_ip<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; s = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_DGRAM</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; s.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;sdo.com&quot;</span>,<span style="color: #ff4500;">80</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> s.<span style="color: black;">getsockname</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span></div></div>
<p>参考 http://stackoverflow.com/questions/166506/finding-local-ip-addresses-in-python</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/06/python%e8%8e%b7%e5%8f%96%e6%9c%ac%e6%9c%baip/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<georss:point>31.2013666 121.6192502</georss:point>	</item>
		<item>
		<title>搞定gwibber</title>
		<link>http://sunng.info/blog/2010/03/%e6%90%9e%e5%ae%9agwibber/</link>
		<comments>http://sunng.info/blog/2010/03/%e6%90%9e%e5%ae%9agwibber/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 04:48:31 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[foss]]></category>
		<category><![CDATA[gwibber]]></category>
		<category><![CDATA[pycurl]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=522</guid>
		<description><![CDATA[升级10.04之后，gwibber2.29开始使用pycurl来处理IO。结果一条更新都拿不下来，为此搜到很多相关、不相关的bug。最后终于自己找到问题，原来是pycurl.setopt方法传入字符串如果是unicode就会报typeerror。而通过gwibber配置界面输入的所有字符都是unicode编码，于是问题也就简单了。做个处理，在 /usr/lib/python2.6/dist-packages/gwibber/microblog/network.py 第18到21行： &#160; &#160; self.curl.setopt&#40;pycurl.URL, str&#40;url&#41;.encode&#40;'ascii'&#41;&#41; &#160; &#160; if username and password: &#160; &#160; &#160; self.curl.setopt&#40;pycurl.USERPWD, &#40;&#34;%s:%s&#34; % &#40;username, password&#41;&#41;.encode&#40;'ascii'&#41;&#41; 另外，使用StatusNet的Twitter兼容API来做Twitter API代理，需要把代理的目录名设置为api，因为/api这个路径是写死在gwibber代码里的。通过界面输入的，只是代理的domain。 说实在的gwibber还是挺烂的。 https://bugs.launchpad.net/bugs/542501 https://bugs.launchpad.net/bugs/543860]]></description>
			<content:encoded><![CDATA[<p>升级10.04之后，gwibber2.29开始使用pycurl来处理IO。结果一条更新都拿不下来，为此搜到很多相关、不相关的bug。最后终于自己找到问题，<strong>原来是pycurl.setopt方法传入字符串如果是unicode就会报typeerror</strong>。而通过gwibber配置界面输入的所有字符都是unicode编码，于是问题也就简单了。做个处理，在 <em>/usr/lib/python2.6/dist-packages/gwibber/microblog/network.py</em> 第18到21行：</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">curl</span>.<span style="color: black;">setopt</span><span style="color: black;">&#40;</span>pycurl.<span style="color: black;">URL</span>, <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ascii'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> username <span style="color: #ff7700;font-weight:bold;">and</span> password:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">curl</span>.<span style="color: black;">setopt</span><span style="color: black;">&#40;</span>pycurl.<span style="color: black;">USERPWD</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;%s:%s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>username, password<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ascii'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></div>
<p>另外，使用StatusNet的Twitter兼容API来做Twitter API代理，需要把代理的目录名设置为api，因为/api这个路径是写死在gwibber代码里的。通过界面输入的，只是代理的domain。</p>
<p>说实在的gwibber还是挺烂的。</p>
<p>https://bugs.launchpad.net/bugs/542501</p>
<p>https://bugs.launchpad.net/bugs/543860</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/03/%e6%90%9e%e5%ae%9agwibber/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
		<item>
		<title>Virtual Machine Searcher for Gnome Deskbar Applet</title>
		<link>http://sunng.info/blog/2010/02/virtual-machine-searcher-for-gnome-deskbar-applet/</link>
		<comments>http://sunng.info/blog/2010/02/virtual-machine-searcher-for-gnome-deskbar-applet/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 08:18:33 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[广告]]></category>
		<category><![CDATA[gnome]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=475</guid>
		<description><![CDATA[Very glad to announce another daily-coding work: an extension for gnome deskbar applet to search and launch virtual machine. There is a plugin for gnome-do that does the same job. That&#8217;s what I create the the plugin for. I switched to deskbar because gnome-do&#8217;s Do.exe reminds me nightmares when I was a M$ Windows user. [...]]]></description>
			<content:encoded><![CDATA[<p>Very glad to announce another daily-coding work: an extension for gnome deskbar applet to search and launch virtual machine. There is a plugin for gnome-do that does the same job. That&#8217;s what I create the the plugin for. I switched to deskbar because gnome-do&#8217;s Do.exe reminds me nightmares when I was a M$ Windows user. The deskbar applet has been a great replacement, however, the virtualbox plugin in Do is really impressive while deskbar doesn&#8217;t provide me the same functionality.</p>
<p>You can ignore words above and just take a look at the screenshot:<br />
<a title="deskbar-virtualbox by 贝小塔, on Flickr" href="http://www.flickr.com/photos/40741608@N08/4350951202/"><img src="http://farm5.static.flickr.com/4062/4350951202_9ede9c4318_o.png" alt="deskbar-virtualbox" width="560" height="400" /></a></p>
<h3>Download</h3>
<p>Download the extension from (the highlighted one):<br />
<a href="http://bitbucket.org/sunng/daily-coding/downloads/?highlight=8792">http://bitbucket.org/sunng/daily-coding/downloads/?highlight=5137</a></p>
<p>You can also trace the development at bitbucket project. However, the repository is mixed with other small code snippets. Currently, mercurial doesn&#8217;t support subdirectory pull. So there is no way to grab the deskbar-applet individually.</p>
<h3>Installation</h3>
<p>copy this file to <em>/usr/lib/deskbar-applet/deskbar-applet/modules-2.20-compatible/</em> (Ubuntu installation for example) with super user privilege. Right click desktbar applet, select Preference, Searchers tab, hit &#8220;Reload&#8221; button, then check the Virtualbox Deskbar Module.<br />
<a title="deskbar-preference by 贝小塔, on Flickr" href="http://www.flickr.com/photos/40741608@N08/4350219097/"><img src="http://farm5.static.flickr.com/4006/4350219097_126cdb3c8d.jpg" alt="deskbar-preference" width="500" height="346" /></a></p>
<h3>Issue</h3>
<p>Feel free the report issues on bitbucket:<br />
<a href="http://bitbucket.org/sunng/daily-coding/issues/">http://bitbucket.org/sunng/daily-coding/issues/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/02/virtual-machine-searcher-for-gnome-deskbar-applet/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
		<item>
		<title>List your installed virtualbox virtual marchines using vbox python xpcom api</title>
		<link>http://sunng.info/blog/2010/02/list-your-installed-virtualbox-virtual-marchines-using-vbox-python-xpcom-api/</link>
		<comments>http://sunng.info/blog/2010/02/list-your-installed-virtualbox-virtual-marchines-using-vbox-python-xpcom-api/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 05:33:51 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[把戏]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[VirtualBox]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=470</guid>
		<description><![CDATA[I&#8217;m sorry for the long title. Due to lack of documentation, it&#8217;s not easy to use python xpcom api from virtualbox sdk. The code below is just a sample that lists your installed virtual machines. It works on linux with VirtualBox OSE 2.0.8. Hope useful to you. import vboxapi vmsg = vboxapi.VirtualBoxManager&#40;None, None&#41; vbox = [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m sorry for the long title. Due to lack of documentation, it&#8217;s not easy to use python xpcom api from virtualbox sdk. The code below is just a sample that lists your installed virtual machines. It works on linux with VirtualBox OSE 2.0.8. Hope useful to you.</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> vboxapi<br />
vmsg = vboxapi.<span style="color: black;">VirtualBoxManager</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span><br />
vbox = vmsg.<span style="color: black;">vbox</span><br />
vmsg.<span style="color: black;">mgr</span>.<span style="color: black;">getSessionObject</span><span style="color: black;">&#40;</span>vbox<span style="color: black;">&#41;</span><br />
machs = vbox.<span style="color: black;">getMachines</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
names = <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: black;">&#40;</span>x.<span style="color: black;">name</span>,x.<span style="color: #008000;">id</span><span style="color: black;">&#41;</span>, machs<span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">print</span> names</div></div>
<p>Output:</p>
<div class="codecolorer-container python default" style="border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'Ubuntu'</span>, u<span style="color: #483d8b;">'aac3fd46-4f1e-4f6e-8abe-b1a5516abf8c'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'Windows'</span>, u<span style="color: #483d8b;">'fa73952e-f0a6-4bf0-af20-259513d73bc1'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'OpenSolaris'</span>, u<span style="color: #483d8b;">'a951542c-3178-4a6b-8087-f1b0314e283a'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'LinuxMint'</span>, u<span style="color: #483d8b;">'8191f256-1b76-4ce7-a202-93730dae1b33'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'Fedora'</span>, u<span style="color: #483d8b;">'ca250f45-d752-4baf-9281-fb0847dc8287'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'Freebsd'</span>, u<span style="color: #483d8b;">'8322b62a-aed5-4f04-9815-9fadfeba9fe1'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'ArchLinux'</span>, u<span style="color: #483d8b;">'efc1167a-4e06-4c14-aeb0-bfb303c8f5f7'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'openSUSE'</span>, u<span style="color: #483d8b;">'02e18816-311d-420b-99b3-6b4b4cccf7b7'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'CentOS'</span>, u<span style="color: #483d8b;">'ccf0421c-85c4-4123-8722-57abc494c633'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></div></div>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/02/list-your-installed-virtualbox-virtual-marchines-using-vbox-python-xpcom-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OAuth Step by Step</title>
		<link>http://sunng.info/blog/2010/01/oauth-step-by-step/</link>
		<comments>http://sunng.info/blog/2010/01/oauth-step-by-step/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 15:47:25 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[mashup]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.classicning.com/blog/?p=420</guid>
		<description><![CDATA[最近琢磨OAuth认证方式。OAuth的优点主要在于﻿ 用户不需要直接提供用户名密码给第三方应用，就可以让第三方应用访问受限资源； 资源提供方对第三方应用有更细粒度的控制。 在整个OAuth协议里，生成signature的base string是最容易出错的部分。它由HTTP方法名、URL编码的请求路径和请求的参数表组成。 请求的参数表是除去oauth_signature以外的所有参数，按参数名排序，并进行url转义 def to_signature_key(method, url, data): keys = list(data.keys()) keys.sort() encoded = urllib.quote("&#38;".join([key+"="+data[key] for key in keys])) return "&#38;".join([method, urllib.quote(url, safe="~"), encoded]) 有了这个通用的生成signature base string的方法，以后就可以根据OAuth协议规范按步骤进行。 首先获取Request Token。这一步通常使用资源提供方注册的API Key和API Key Secret def request_token_params(consumer_key, consumer_secret, path, method='GET'): data={} data['oauth_consumer_key']=consumer_key data['oauth_signature_method']='HMAC-SHA1' data['oauth_timestamp']=str(int(time.time())) data['oauth_nonce']=''.join([str(random.randint(0,9)) for i in range(10)]) print data msg = to_signature_key(method, path, data) [...]]]></description>
			<content:encoded><![CDATA[<p>最近琢磨OAuth认证方式。OAuth的优点主要在于﻿</p>
<ul>
<li>用户不需要直接提供用户名密码给第三方应用，就可以让第三方应用访问受限资源；</li>
<li>资源提供方对第三方应用有更细粒度的控制。</li>
</ul>
<p>在整个OAuth协议里，生成signature的base string是最容易出错的部分。它由HTTP方法名、URL编码的请求路径和请求的参数表组成。<br />
请求的参数表是除去oauth_signature以外的所有参数，按参数名排序，并进行url转义</p>
<pre class="brush:python">def to_signature_key(method, url, data):
	keys = list(data.keys())
	keys.sort()
	encoded = urllib.quote("&amp;".join([key+"="+data[key] for key in keys]))
	return "&amp;".join([method, urllib.quote(url, safe="~"), encoded])
</pre>
<p>有了这个通用的生成signature base string的方法，以后就可以根据OAuth协议规范按步骤进行。</p>
<p>首先获取Request Token。这一步通常使用资源提供方注册的API Key和API Key Secret</p>
<pre class="brush:python">def request_token_params(consumer_key, consumer_secret, path, method='GET'):
	data={}
	data['oauth_consumer_key']=consumer_key
	data['oauth_signature_method']='HMAC-SHA1'
	data['oauth_timestamp']=str(int(time.time()))
	data['oauth_nonce']=''.join([str(random.randint(0,9)) for i in range(10)])
	print data

	msg = to_signature_key(method, path, data)
	print msg

	signed = base64.b64encode(hmac.new(consumer_secret+"&amp;", msg, hashlib.sha1).digest())
	print signed
	data['oauth_signature']=signed
	return data

def result2dict(result_string):
	d = {}
	params = res.split('&amp;')
	for p in params:
		d[p.split('=')[0]] = p.split('=')[1]
	return d

conn = httplib.HTTPConnection("www.douban.com", 80)

params = request_token_params(consumer_key, consumer_secret, request_token_path)
conn.request('GET', request_token_path+"?"+urllib.urlencode(params))
res = conn.getresponse().read()
print res
request_token = result2dict(res)
</pre>
<p>这一步可以获得未经认证的Request Token和Request Token Secret。需要注意的细节是在计算hmac签名的时候，即使只有一个Token Secret，仍然需要加上&#8221;&amp;&#8221;</p>
<p>第二步要求用户授权该Request Token，打开浏览器，将用户定向到相应的授权页面，参数为上一步获得的Request Token</p>
<p>第三步，用授权过的Request Token换取Access Token。这一步类似第一步，只是用于签名的token包括API Key Secret和Request Token</p>
<pre class="brush:python">def access_token_params(consumer_key, consumer_secret, oauth_token, oauth_secret, path, method='GET'):
	data={}
	data['oauth_consumer_key']=consumer_key
	data['oauth_signature_method']='HMAC-SHA1'
	data['oauth_timestamp']=str(int(time.time()))
	data['oauth_nonce']=''.join([str(random.randint(0,9)) for i in range(10)])
	data['oauth_token'] = oauth_token

	msg = to_signature_key(method, path, data)
	print msg

	signed = base64.b64encode(hmac.new(consumer_secret+"&amp;"+oauth_secret, msg, hashlib.sha1).digest())
	print signed
	data['oauth_signature']=signed
	return data

params = access_token_params(consumer_key, consumer_secret, request_token['oauth_token'],
	request_token['oauth_token_secret'], access_token_path)
conn.request('GET', access_token_path+"?"+urllib.urlencode(params))
res = conn.getresponse().read()
print res
access_token = result2dict(res)
</pre>
<p>这一步将至少返回Access Token和Access Token Secret，是最终用于访问受限资源的Token。以豆瓣的实现为例，OAuth的相关参数应放在HTTP头里随请求进行发送。</p>
<pre class="brush:python">def oauth_header(consumer_key, consumer_secret, oauth_token, oauth_secret, path, realm):
	data = access_token_params(consumer_key, consumer_secret, oauth_token, oauth_secret, path, method="POST")
	header_string = ','.join([key+'="'+data[key]+'"' for key in data.keys()])
	return 'OAuth realm="'+realm+'",'+header_string

posturl = 'http://api.douban.com/miniblog/saying'

content = """&lt;?xml version='1.0' encoding='UTF-8'?&gt;
&lt;entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/"&gt;
&lt;content&gt;li lei ju le han mei mei&lt;/content&gt;
&lt;/entry&gt;
"""

header = {}
header['Authorization'] = oauth_header(consumer_key, consumer_secret,
		access_token['oauth_token'], access_token['oauth_token_secret'],
		posturl, "http://api.douban.com")
header['Content-Type'] = 'application/atom+xml'
print header

conn.request('POST', posturl, content, header)
res = conn.getresponse().read()

print res

conn.close()
</pre>
<p>在这一步中，用于生成signature base string的url是要访问的受限资源地址，而签名的参数表依然是oauth相关的参数。<br />
生成的Authorization头如下</p>
<pre class="brush:text">Authorization: OAuth realm="http://api.douban.com",
    oauth_nonce="8735717688",
    oauth_timestamp="1262613619",
    oauth_consumer_key="0bc081a01168b263234184e0343a1729",
    oauth_signature_method="HMAC-SHA1",
    oauth_token="5fb836c37543ad691f28a44a5fcb083b",
    oauth_signature="jk6p5qaXVPrGQctSzpO5jjYHfDk="
</pre>
<p>用这个头就可以在一定的时间内访问所有授权范围内的受限资源。</p>
<p>代码是ugly了一些，不过应该相对易于理解吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/01/oauth-step-by-step/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
	</channel>
</rss>
