<?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; project</title>
	<atom:link href="http://sunng.info/blog/tag/project/feed/" rel="self" type="application/rss+xml" />
	<link>http://sunng.info/blog</link>
	<description>47% users on this site use *nix</description>
	<lastBuildDate>Sat, 04 Feb 2012 13:08:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Slacker Cluster</title>
		<link>http://sunng.info/blog/2012/02/slacker-cluster/</link>
		<comments>http://sunng.info/blog/2012/02/slacker-cluster/#comments</comments>
		<pubDate>Sat, 04 Feb 2012 13:08:19 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[slacker]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1161</guid>
		<description><![CDATA[Cluster support is one of the big thing in slacker 0.6.x. Cluster enables high-availability and load balancing on slacker client and server. Slacker cluster has a centralized registry, a zookeeper node, stores information of all the namespaces and servers instances &#8230; <a href="http://sunng.info/blog/2012/02/slacker-cluster/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Cluster support is one of the big thing in slacker 0.6.x. Cluster enables high-availability and load balancing on slacker client and server. </p>
<p>Slacker cluster has a centralized registry, a zookeeper node, stores information of all the namespaces and servers instances in the cluster. Once a client declared remote functions, by calling `defn-remote` or `use-remote`, it reads all available servers offering that namespace from the registry and create connection to each of them. We the user issues a request, the client randomly pick up a connection from them. So the load is eventually distributed to every instance of slacker servers. And thanks to zookeeper&#8217;s notification feature, the client watches certain znode. It will be notified when 1. a connected server goes offline 2. a new server serving required namespace added into the cluster. Thus you don&#8217;t have to change client code or restart client when server changes. </p>
<p>To start a slacker server and add it to a cluster, you have to provide cluster information using the new <strong>:cluster</strong> option:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>start<span style="color: #66cc66;">-</span>slacker<span style="color: #66cc66;">-</span>server <span style="color: #66cc66;">&#40;</span>the<span style="color: #66cc66;">-</span><span style="color: #b1b100;">ns</span> 'slacker<span style="color: #66cc66;">.</span>example<span style="color: #66cc66;">.</span>api<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #cc66cc;">2104</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :<span style="color: #555;">cluster</span> <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">zk</span> <span style="color: #ff0000;">&quot;127.0.0.1:2181&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :<span style="color: #555;">name</span> <span style="color: #ff0000;">&quot;example-cluster&quot;</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span></div></div>
<ul>
<li>:zk is the address of zookeeper node</li>
<li>:name is a znode qualified string, to identify the cluster</li>
</ul>
<p>On the client side, it&#8217;s important to use APIs from `slacker.client.cluster` instead of `slacker.client`:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>use 'slacker<span style="color: #66cc66;">.</span>client<span style="color: #66cc66;">.</span>cluster<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #808080; font-style: italic;">;; arguments: cluster-name, zookeeper address</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> sc <span style="color: #66cc66;">&#40;</span>clustered<span style="color: #66cc66;">-</span>slackerc <span style="color: #ff0000;">&quot;example-cluster&quot;</span> <span style="color: #ff0000;">&quot;127.0.0.1:2181&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>use<span style="color: #66cc66;">-</span>remote 'sc 'slacker<span style="color: #66cc66;">.</span>example<span style="color: #66cc66;">.</span>api<span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #808080; font-style: italic;">;; call the function from a random server</span><br />
<span style="color: #66cc66;">&#40;</span>timestamp<span style="color: #66cc66;">&#41;</span></div></div>
<p>If all servers provide &#8216;slacker.example.api go offline, slacker client will raise a &#8220;not-found&#8221; exception.</p>
<p>Slacker cluster is also designed with simple and clean in mind. You don&#8217;t have to change you business code to make it remote or cluster. Everything is transparent and non-invasive. Enjoy it.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/02/slacker-cluster/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Slacker 0.6: Exposing multiple namespaces</title>
		<link>http://sunng.info/blog/2012/02/slacker-0-6-exposing-multiple-namespaces/</link>
		<comments>http://sunng.info/blog/2012/02/slacker-0-6-exposing-multiple-namespaces/#comments</comments>
		<pubDate>Fri, 03 Feb 2012 14:14:34 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[slacker]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1154</guid>
		<description><![CDATA[After 98 commits in about one month, I&#8217;m glad to announce [slacker "0.6.1"]. One thing in slacker 0.6.x is you can expose multiple namespaces from a single server. Suppose you have two namespaces `redday.stats` and `redday.api`, both contains functions you &#8230; <a href="http://sunng.info/blog/2012/02/slacker-0-6-exposing-multiple-namespaces/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>After <a href="https://github.com/sunng87/slacker/compare/8b4abdb62a...3e41e035b9" title="Changes">98 commits</a> in about one month, I&#8217;m glad to announce [slacker "0.6.1"].</p>
<p>One thing in slacker 0.6.x is you can expose multiple namespaces from a single server.</p>
<p>Suppose you have two namespaces `redday.stats` and `redday.api`, both contains functions you want to expose.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #66cc66;">&#40;</span>start<span style="color: #66cc66;">-</span>slacker<span style="color: #66cc66;">-</span>server <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#40;</span>the<span style="color: #66cc66;">-</span><span style="color: #b1b100;">ns</span> 'redday<span style="color: #66cc66;">.</span>stats<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #66cc66;">&#40;</span>the<span style="color: #66cc66;">-</span><span style="color: #b1b100;">ns</span> 'redday<span style="color: #66cc66;">.</span>api<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #cc66cc;">6565</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>This will expose `redday.stats` and `redday.api` on port 6565.</p>
<p>On the client side, we have a new `use-remote` behaviors like clojure&#8217;s use. Instead of local one, it imports functions from a remote namespace to your current namespace.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>use 'slacker<span style="color: #66cc66;">.</span>client<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #808080; font-style: italic;">;; create a slacker client</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> scp <span style="color: #66cc66;">&#40;</span>slackerc <span style="color: #ff0000;">&quot;127.0.0.1:6565&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <br />
<br />
<span style="color: #66cc66;">&#40;</span>use<span style="color: #66cc66;">-</span>remote 'scp 'redday<span style="color: #66cc66;">.</span>api<span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; caution, use the symbol of 'scp here </span><br />
<span style="color: #66cc66;">&#40;</span>use<span style="color: #66cc66;">-</span>remote 'scp 'redday<span style="color: #66cc66;">.</span>stats<span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #808080; font-style: italic;">;;top-titles is a function in redday.api</span><br />
<span style="color: #808080; font-style: italic;">;;now you can use the remote function transparently</span><br />
<span style="color: #66cc66;">&#40;</span>top<span style="color: #66cc66;">-</span>titles <span style="color: #ff0000;">&quot;programming&quot;</span><span style="color: #66cc66;">&#41;</span> <br />
<br />
<span style="color: #808080; font-style: italic;">;;check function metadata you can find more slacker properties</span><br />
<span style="color: #66cc66;">&#40;</span>meta top<span style="color: #66cc66;">-</span>titles<span style="color: #66cc66;">&#41;</span></div></div>
<p>If you need to configure callback to a particular function, you can still use `defn-remote` to specify the callback function. In slacker 0.6.0, a `:remote-ns` is required when you define such a remote function.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defn<span style="color: #66cc66;">-</span>remote top<span style="color: #66cc66;">-</span>titles :<span style="color: #555;">remote</span><span style="color: #66cc66;">-</span><span style="color: #b1b100;">ns</span> <span style="color: #ff0000;">&quot;redday.api&quot;</span> :<span style="color: #555;">callback</span> #<span style="color: #66cc66;">&#40;</span>println <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>The complete code example (both server and client) can be found <a href="https://bitbucket.org/sunng/slacker-demo/overview">here</a>. </p>
<p>In next post, I will explain another big new feature of 0.6.x, cluster support.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/02/slacker-0-6-exposing-multiple-namespaces/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ClojureDocs Android App</title>
		<link>http://sunng.info/blog/2012/01/clojuredocs-android-app/</link>
		<comments>http://sunng.info/blog/2012/01/clojuredocs-android-app/#comments</comments>
		<pubDate>Tue, 24 Jan 2012 08:34:56 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[project]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1145</guid>
		<description><![CDATA[利用春节的假期写了一个Android应用，可以在ClojureDocs.org上搜索clojure API，浏览文档、源代码和社区贡献的代码实例。ClojureDocs在我学习Clojure的过程中起了很大的作用，所以我想这个网站应该对很多人有用。 无暇去学习Android平台上繁琐的知识，不过好在有Phonegap这样的框架，可以把网页应用转化为本地应用，并且提供访问本地设备的API。通过Phonegap开发的程序还可以直接移植到iphone平台上。ClojureDocs Android就是运行在Phonegap中。 首页： 搜索界面 API函数界面 你可以从github获得代码和签名过的apk：https://github.com/sunng87/clojuredocs-android Known Issue，phonegap程序在屏幕旋转时会崩溃，已经在2.3和3.2上重现，目前还不清楚具体的原因。(Edit 20120127: Fixed in 1.0.4) 欢迎任何的pull request。]]></description>
			<content:encoded><![CDATA[<p>利用春节的假期写了一个Android应用，可以在<a href="http://clojuredocs.org" target="_blank">ClojureDocs.org</a>上搜索clojure API，浏览文档、源代码和社区贡献的代码实例。ClojureDocs在我学习Clojure的过程中起了很大的作用，所以我想这个网站应该对很多人有用。</p>
<p>无暇去学习Android平台上繁琐的知识，不过好在有Phonegap这样的框架，可以把网页应用转化为本地应用，并且提供访问本地设备的API。通过Phonegap开发的程序还可以直接移植到iphone平台上。ClojureDocs Android就是运行在Phonegap中。</p>
<p>首页：<br />
<img src="http://i.imgur.com/zdMCt.png" alt="" /></p>
<p>搜索界面<br />
<img src="http://i.imgur.com/MVCz4.png" alt="" /></p>
<p>API函数界面<br />
<img src="http://i.imgur.com/M0fEI.png" alt="" /></p>
<p>你可以从github获得代码和签名过的apk：<a href="https://github.com/sunng87/clojuredocs-android" target="_blank">https://github.com/sunng87/clojuredocs-android</a></p>
<p>Known Issue，phonegap程序在屏幕旋转时会崩溃，已经在2.3和3.2上重现，目前还不清楚具体的原因。(Edit 20120127: Fixed in 1.0.4)</p>
<p>欢迎任何的pull request。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/01/clojuredocs-android-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Weekend Project: LazyPress</title>
		<link>http://sunng.info/blog/2012/01/weekend-project-lazypress/</link>
		<comments>http://sunng.info/blog/2012/01/weekend-project-lazypress/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 07:40:01 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[cloudfoundry]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1134</guid>
		<description><![CDATA[发布一个典型的weekend project, 名字叫做LazyPress.顾名思义,这是一个在线的写作系统. 取名Lazy, 除了因为它用Clojure写成,更因为他的简单: 没有繁琐的注册,没有繁琐的分类tag,没有繁琐的格式化,无论是使用还是开发都力求做到最简单. LazyPress采用Mozilla刚刚发布的BrowserID. 技术作为账号系统, 用户只需要在首次登录后提供一个ID即可(原本这一步也可以省略, 但是为了保护您的邮箱隐私, 现在需要一个LazyPress专用的ID). 这样LazyPress本身不存储用户的密码,也简化了用户账号管理的代价. BrowserID的登录流程非常简单, 速度也比传统的OpenID和OAuth要快, 用户体验要比多次跳转好很多. LazyPress使用Markdown进行文本格式化, 简单的编辑器可以支持绝大多数格式的要求. 另外,在浏览器后台LazyPress使用HTML5 LocalStorage技术自动保存用户的文本草稿, 如果用户没有成功发布, 可以在下次浏览器打开时进行恢复. LazyPress后台存储采用mongodb. 正是mongodb的schema free特性降低了项目功能重构的成本, 促进了人们更快更频繁地优化产品的模型. 这应该是文档型数据库之于传统关系型数据库最大的优势. (犹如git之于svn, 开分支的成本要低得多, 看似是一个普通的功能改进, 实则鼓励促进了开发人员通过开分支实现自己的修改) LazyPress运行在最近发布的compojure 1.0.0和ring 1.0.0上, 打包为标准的Java web应用直接部署在cloudfoundry上. 前端继续使用的是我偏爱的Mootools库, 因为使用了很多新的浏览器技术, 所以目前只能保证在最新的Firefox和Chromium/Chrome上正常使用. Fork me &#8230; <a href="http://sunng.info/blog/2012/01/weekend-project-lazypress/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>发布一个典型的weekend project, 名字叫做<a href="http://lazypress.cloundfoundry.com">LazyPress</a>.顾名思义,这是一个在线的写作系统. 取名Lazy, 除了因为它用Clojure写成,更因为他的简单: 没有繁琐的注册,没有繁琐的分类tag,没有繁琐的格式化,无论是使用还是开发都力求做到最简单.<br />
LazyPress采用Mozilla刚刚发布的<a href="http://browserid.org/">BrowserID</a>. 技术作为账号系统, 用户只需要在首次登录后提供一个ID即可(原本这一步也可以省略, 但是为了保护您的邮箱隐私, 现在需要一个LazyPress专用的ID). 这样LazyPress本身不存储用户的密码,也简化了用户账号管理的代价. BrowserID的登录流程非常简单, 速度也比传统的OpenID和OAuth要快, 用户体验要比多次跳转好很多.<br />
LazyPress使用Markdown进行文本格式化, 简单的编辑器可以支持绝大多数格式的要求. 另外,在浏览器后台LazyPress使用HTML5 LocalStorage技术自动保存用户的文本草稿, 如果用户没有成功发布, 可以在下次浏览器打开时进行恢复.</p>
<p>LazyPress后台存储采用mongodb. 正是mongodb的schema free特性降低了项目功能重构的成本, 促进了人们更快更频繁地优化产品的模型. 这应该是文档型数据库之于传统关系型数据库最大的优势. (犹如git之于svn, 开分支的成本要低得多, 看似是一个普通的功能改进, 实则鼓励促进了开发人员通过开分支实现自己的修改)<br />
LazyPress运行在最近发布的compojure 1.0.0和ring 1.0.0上, 打包为标准的Java web应用直接部署在cloudfoundry上. 前端继续使用的是我偏爱的Mootools库, 因为使用了很多新的浏览器技术, 所以目前只能保证在最新的Firefox和Chromium/Chrome上正常使用.</p>
<p>Fork me on github: <a href="http://github.com/sunng87/lazypress">http://github.com/sunng87/lazypress</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/01/weekend-project-lazypress/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>slacker 0.4.0 released</title>
		<link>http://sunng.info/blog/2012/01/slacker-0-4-0-released/</link>
		<comments>http://sunng.info/blog/2012/01/slacker-0-4-0-released/#comments</comments>
		<pubDate>Wed, 04 Jan 2012 12:49:04 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[slacker]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1132</guid>
		<description><![CDATA[Slacker 0.4.0 has been released to clojars.org . There are new features and breaking changes in this release. Breaking Changes New maven coordinator: [slacker "0.4.0"] (groupId renamed to slakcer) defremote renamed to defn-remote SlackerException removed. slacker now uses slingshot for &#8230; <a href="http://sunng.info/blog/2012/01/slacker-0-4-0-released/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Slacker 0.4.0 has been released to clojars.org . There are new features and breaking changes in this release.</p>
<h3>Breaking Changes</h3>
<ul>
<li>New maven coordinator: [slacker "0.4.0"] (groupId renamed to slakcer)</li>
<li>defremote renamed to <strong>defn-remote</strong></li>
<li>SlackerException removed. slacker now uses slingshot for exception handling</li>
<li>Rename :async option of defn-remote to <strong>:async?</strong></li>
</ul>
<h3>What&#8217;s new in 0.4.0</h3>
<ul>
<li>Add new serialization type <strong>:clj</strong></li>
<li>New interceptors: execution time stats, args logger, slow watch dog</li>
<li>New HTTP interface</li>
<li>Server inspect commands	</li>
<li> utility functions/macros <strong>defn-remote-all</strong>, <strong>defn-remote-batch</strong> and <strong>meta-remote</strong></li>
</ul>
<p>Get more information on <a href="https://github.com/sunng87/slacker" target="_blank">github</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/01/slacker-0-4-0-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extend slacker server with interceptors</title>
		<link>http://sunng.info/blog/2011/12/extend-slacker-server-with-interceptors/</link>
		<comments>http://sunng.info/blog/2011/12/extend-slacker-server-with-interceptors/#comments</comments>
		<pubDate>Sun, 18 Dec 2011 10:08:42 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[装备]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[slacker]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1106</guid>
		<description><![CDATA[An interceptor framework was introduced in slacker 0.3.0. It&#8217;s designed to allow user to add custom functionality without hacking into the internal of slacker. Like many server frameworks, slacker abstracts the request processing as a pipeline. The request object is &#8230; <a href="http://sunng.info/blog/2011/12/extend-slacker-server-with-interceptors/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>An interceptor framework was introduced in slacker 0.3.0. It&#8217;s designed to allow user to add custom functionality without hacking into the internal of slacker.</p>
<p>Like many server frameworks, slacker abstracts the request processing as a pipeline. The request object is modified by adding or updating attributes through each node of the pipeline. So it&#8217;s easy to add your interceptor into the pipeline, with which you can get the data before and after function executed.</p>
<p>To create such an interceptor, you should use the <em>slacker.interceptor/definterceptor</em> macro and <em>slacker.interceptor/definterceptor+</em> macro:</p>
<blockquote><p>(definterceptor name<br />
  :before interceptor-function<br />
  :after interceptor-function)</p></blockquote>
<blockquote><p>(definterceptor+ name [arguments]<br />
  :before interceptor-function<br />
  :after interceptor-function)</p></blockquote>
<p>definterceptor+ can accept arguments so you can configure the interceptor when you use it.</p>
<p>See a simple example:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>definterceptor log<span style="color: #66cc66;">-</span>function<span style="color: #66cc66;">-</span>call<br />
&nbsp; :<span style="color: #555;">before</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>req<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>println <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">str</span> <span style="color: #ff0000;">&quot;calling &quot;</span> <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">fname</span> req<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> req<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #66cc66;">&#40;</span>definterceptor<span style="color: #66cc66;">+</span> log<span style="color: #66cc66;">-</span>function<span style="color: #66cc66;">-</span>call<span style="color: #66cc66;">-</span>prefixed <span style="color: #66cc66;">&#91;</span>prefix<span style="color: #66cc66;">&#93;</span><br />
&nbsp; :<span style="color: #555;">before</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>req<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>println <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">str</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span>? prefix<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>prefix<span style="color: #66cc66;">&#41;</span> prefix<span style="color: #66cc66;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #ff0000;">&quot; calling &quot;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">fname</span> req<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>Then, add it to your slacker server by</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>use '<span style="color: #66cc66;">&#91;</span>slacker<span style="color: #66cc66;">.</span>interceptor<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">import</span> '<span style="color: #66cc66;">&#91;</span>java<span style="color: #66cc66;">.</span>util Date<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>start<span style="color: #66cc66;">-</span>slacker <span style="color: #66cc66;">&#40;</span>the<span style="color: #66cc66;">-</span><span style="color: #b1b100;">ns</span> 'slapi<span style="color: #66cc66;">&#41;</span> <span style="color: #cc66cc;">2104</span><br />
&nbsp; :<span style="color: #555;">interceptors</span> <span style="color: #66cc66;">&#40;</span>interceptors log<span style="color: #66cc66;">-</span>function<span style="color: #66cc66;">-</span>call<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span>log<span style="color: #66cc66;">-</span>function<span style="color: #66cc66;">-</span>call<span style="color: #66cc66;">-</span>prefixed <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">.</span>toString <span style="color: #66cc66;">&#40;</span>Date<span style="color: #66cc66;">.</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>Now you can log every function call of your slacker server.</p>
<p>For more detail about the interceptor framework, especially the request data, please check the <a href="https://github.com/sunng87/slacker/wiki/Interceptors" target="_blank">wiki page</a>.</p>
<p>In slacker 0.3.0, there is a built-in interceptor to stats function calls. You can find it at <em>slacker.interceptors.stats</em>. The stats data is expose via JMX. You can also write monitoring application to retrieve the data.<br />
<a href="http://imgur.com/vtOoL"><img src="http://i.imgur.com/vtOoL.png" alt="" title="Hosted by imgur.com" /></a></p>
<p>And there will be more built-in interceptors in 0.4.0, includes function call time stats and logging.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/extend-slacker-server-with-interceptors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>slacker 0.2.0 is out</title>
		<link>http://sunng.info/blog/2011/12/slacker-0-2-0-is-out/</link>
		<comments>http://sunng.info/blog/2011/12/slacker-0-2-0-is-out/#comments</comments>
		<pubDate>Sat, 10 Dec 2011 09:27:16 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[slacker]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1090</guid>
		<description><![CDATA[Slacker 0.2.0 has been pushed to clojars today. Connection pooling and json serialization are available in this release. Connection Pool Generally, pooling connection is a good idea in high concurrence application. To make slacker for real world, connection pool support &#8230; <a href="http://sunng.info/blog/2011/12/slacker-0-2-0-is-out/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="https://github.com/sunng87/slacker">Slacker 0.2.0</a> has been pushed to clojars today. Connection pooling and json serialization are available in this release.</p>
<h4>Connection Pool</h4>
<p>Generally, pooling connection is a good idea in high concurrence application. To make slacker for real world, connection pool support is a high-prioritized feature in its development. The new connection pool is backended by commons-pool which you might familiar with. To use connection pool, just create slacker client with a new function `slackerc-pool`</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> scp <span style="color: #66cc66;">&#40;</span>slackerc<span style="color: #66cc66;">-</span>pool <span style="color: #ff0000;">&quot;localhost&quot;</span> <span style="color: #cc66cc;">2104</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>Then you can use this pool just like a single client.</p>
<p>Some options are available to configure the pool by your wish:</p>
<ul>
<li><em>:max-active</em>, max connections opened by the pool</li>
<li><em>:exhausted-action</em>
<ul>
<li><em>:fail</em> throw an exception when pool exhausted.</li>
<li><em>:block</em> block current thread and wait until max-wait exceed (throw an exception)</li>
<li><em>:grow</em> automatically create new connection and add it to pool</li>
</ul>
</li>
<li><em>:max-wait</em> max wait time before throwing an exception</li>
<li><em>:min-idle</em> minimal number of pool hold idle connections </li>
</ul>
<p>The options are inherited from GenericObjectPool, you can find detailed information from their <a href="http://commons.apache.org/pool/apidocs/org/apache/commons/pool/impl/GenericObjectPool.html">javadoc</a>.</p>
<h4>JSON Serialization</h4>
<p>slacker just added json serialization provided by clj-json. According to my test, clj-json is 1x faster than carbonite in serialization.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> sc <span style="color: #66cc66;">&#40;</span>slackerc <span style="color: #ff0000;">&quot;localhost&quot;</span> <span style="color: #cc66cc;">2104</span> :<span style="color: #555;">content</span><span style="color: #66cc66;">-</span>type :<span style="color: #555;">json</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>However, with json serialization, you may lost some clojure types like keyword and set in type conversion. You should be caution when using json as serialization method. </p>
<p>In next release, I am planning to use <a href="https://github.com/AlibabaTech/fastjson/" target="_blank">fastjson</a> as json lib which provides option to write type name into json so it could be a full featured serialization for clojure. And fastjson is claimed even faster than jackson.</p>
<h4>Performance</h4>
<p>slacker gains high performance with its non-blocking server, serialization and direct function call. As tested on a dual 6 core server,  it reaches 10000+ TPS for a single client (50 connections, 50 threads). The server just use 35% CPU so I consider it could have even more TPS if there is two or more client machines.</p>
<p>So if you are interested in some benchmarks, you can test it with client like <a href="https://gist.github.com/1449860" target="_blank">this</a>. All the requests are using synchronous call because I believe it&#8217;s the most common case you use slacker.</p>
<h4>Next steps</h4>
<p>Inspired by discussion in <a href="http://groups.google.com/group/cn-clojure" target="_blank">cn-clojure</a> mailing list, I&#8217;m going to add HTTP transport for slacker. With HTTP transport, it&#8217;s easier to debug and evaluate your clojure functions, it also makes slacker available to ClojureScript. </p>
<p>At lst, thanks Zach Tellman for reviewing my client code. </p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/slacker-0-2-0-is-out/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>从GNOME网站安装exaile-doubanfm-gnome-shell-extension</title>
		<link>http://sunng.info/blog/2011/12/%e4%bb%8egnome%e7%bd%91%e7%ab%99%e5%ae%89%e8%a3%85exaile-doubanfm-gnome-shell-extension/</link>
		<comments>http://sunng.info/blog/2011/12/%e4%bb%8egnome%e7%bd%91%e7%ab%99%e5%ae%89%e8%a3%85exaile-doubanfm-gnome-shell-extension/#comments</comments>
		<pubDate>Sat, 03 Dec 2011 06:06:59 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[装备]]></category>
		<category><![CDATA[gnome]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[project]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1088</guid>
		<description><![CDATA[最近GNOME发布了期待已久的extension.gnome.org，这个网站允许你直接通过浏览器安装和管理gnome-shell扩展，有点类似app store的感觉，混乱的~/.local/share/gnome-shell/extensions/终于有了一个官方的界面。 网站开通的第一时间，我提交了exaile-doubanfm-gnome-shell-extension，经过review和修改，这个扩展也得到了进一步的完善，适配了gnome-shell 3.2的风格。 你可以从这个地址直接安装启用 https://extensions.gnome.org/extension/24/exaile-doubanfm-control/ 它会在exaile douban.fm启动后显示一个菜单在gnome-shell上，你可以通过这个菜单进行基本的操作。 如果喜欢，别忘了在extension.gnome.org上vote一下 ：）]]></description>
			<content:encoded><![CDATA[<p>最近GNOME发布了期待已久的extension.gnome.org，这个网站允许你直接通过浏览器安装和管理gnome-shell扩展，有点类似app store的感觉，混乱的~/.local/share/gnome-shell/extensions/终于有了一个官方的界面。</p>
<p>网站开通的第一时间，我提交了exaile-doubanfm-gnome-shell-extension，经过review和修改，这个扩展也得到了进一步的完善，适配了gnome-shell 3.2的风格。</p>
<p>你可以从这个地址直接安装启用<br />
<a href="https://extensions.gnome.org/extension/24/exaile-doubanfm-control/" target="_blank">https://extensions.gnome.org/extension/24/exaile-doubanfm-control/</a></p>
<p>它会在exaile douban.fm启动后显示一个菜单在gnome-shell上，你可以通过这个菜单进行基本的操作。</p>
<p>如果喜欢，别忘了在extension.gnome.org上vote一下 ：）</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/%e4%bb%8egnome%e7%bd%91%e7%ab%99%e5%ae%89%e8%a3%85exaile-doubanfm-gnome-shell-extension/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Slacker 0.1.0 is out</title>
		<link>http://sunng.info/blog/2011/12/slacker-0-1-0-is-out/</link>
		<comments>http://sunng.info/blog/2011/12/slacker-0-1-0-is-out/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 13:00:05 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[project]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1085</guid>
		<description><![CDATA[Glad to roll out the first release of the slacker framework. Slacker is a clojure RPC framework on top of a TCP binary protocol. It provides a set of non-invasive APIs for both server and client. The remote invocation is &#8230; <a href="http://sunng.info/blog/2011/12/slacker-0-1-0-is-out/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Glad to roll out the first release of the <strong>slacker</strong> framework. Slacker is a clojure RPC framework on top of a TCP binary protocol. It provides a set of non-invasive APIs for both server and client. The remote invocation is completely transparent to user.</p>
<p>In addition to APIs introduced in <a href="http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/">last post</a>, asynchronous approach is supported in client API :</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defremote remote<span style="color: #66cc66;">-</span>func :<span style="color: #555;">async</span> true<span style="color: #66cc66;">&#41;</span><br />
@<span style="color: #66cc66;">&#40;</span>remote<span style="color: #66cc66;">-</span>func<span style="color: #66cc66;">&#41;</span></div></div>
<p>If you add option `:async` to defremote, then the function facade will return a promise. You have to deref it by yourself. Also you can use the `:callback` option in defremote to specify a callback function.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defremote remote<span style="color: #66cc66;">-</span>func :<span style="color: #555;">callback</span> #<span style="color: #66cc66;">&#40;</span>println <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>remote<span style="color: #66cc66;">-</span>func<span style="color: #66cc66;">&#41;</span></div></div>
<p>This gives you much more flexibility of using remote function. But be careful it will break consistency between local and remote mode. </p>
<p>To use slacker, add it to your project.clj</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">:<span style="color: #555;">dependencies</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>info<span style="color: #66cc66;">.</span>sunng<span style="color: #66cc66;">/</span>slacker <span style="color: #ff0000;">&quot;0.1.0&quot;</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span></div></div>
<p>You can find examples on the <a href="https://github.com/sunng87/slacker" target="_blank">github page</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/slacker-0-1-0-is-out/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Exaile豆瓣电台插件0.0.11发布</title>
		<link>http://sunng.info/blog/2011/12/exaile%e8%b1%86%e7%93%a3%e7%94%b5%e5%8f%b0%e6%8f%92%e4%bb%b60-0-11%e5%8f%91%e5%b8%83/</link>
		<comments>http://sunng.info/blog/2011/12/exaile%e8%b1%86%e7%93%a3%e7%94%b5%e5%8f%b0%e6%8f%92%e4%bb%b60-0-11%e5%8f%91%e5%b8%83/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 15:56:45 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[ANN]]></category>
		<category><![CDATA[Douban]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1083</guid>
		<description><![CDATA[很高兴时隔半年后我继续发布了Exaile豆瓣电台插件的更新，从第一个版本发布到现在已经有一年半的时间，这期间豆瓣电台插件已经陆续出现在Rhythmbox、Banshee等播放器上。作为第一个视图把豆瓣电台移植到本地的尝试，我感到甚是欣慰：） 这次的更新修正了长久依赖困绕用户登录问题，现在我们有一个专门的界面来输入验证码。这个功能要感谢DigitalPig用户在github的报告（鞭策作用），此外，我参考了豆瓣电台banshee插件的实现，节省了研究含验证码登录的时间，感谢。总而言之，没有用户的推动，这个项目也不会坚持这么久。 除此之外，插件还有一些支持了新的豆瓣说的推荐，优化了播放列表载入的策略。 另外值得highlight的是，对应的gnome-shell扩展发布了0.0.2版本，唯一的更新是专辑封面现在会显示在gnome-shell的菜单中。 你可以从github获得最新的插件和gnome-shell扩展： exaile-doubanfm-plugin 0.0.11-captcha: https://github.com/sunng87/exaile-doubanfm-plugin/downloads exaile-doubanfm-gnome-shell-extension 0.0.2: https://github.com/sunng87/exaile-doubanfm-gnome-shell-extension/tarball/0.0.2 安装豆瓣电台插件请参考这里。gnome-shell扩展直接解压至~/.local/share/gnome-shell/extensions/即可 有任何问题都可以在github或这里留言。]]></description>
			<content:encoded><![CDATA[<p>很高兴时隔半年后我继续发布了Exaile豆瓣电台插件的更新，从第一个版本发布到现在已经有一年半的时间，这期间豆瓣电台插件已经陆续出现在Rhythmbox、Banshee等播放器上。作为第一个视图把豆瓣电台移植到本地的尝试，我感到甚是欣慰：）</p>
<p>这次的更新修正了长久依赖困绕用户登录问题，现在我们有一个专门的界面来输入验证码。这个功能要感谢<a href="https://github.com/sunng87/exaile-doubanfm-plugin/issues/8">DigitalPig</a>用户在github的报告（鞭策作用），此外，我参考了<a href="http://code.google.com/p/banshee-doubanfm/">豆瓣电台banshee插件</a>的实现，节省了研究含验证码登录的时间，感谢。总而言之，没有用户的推动，这个项目也不会坚持这么久。<br />
<img src="http://i.imgur.com/cYNrM.png" alt="" /></p>
<p>除此之外，插件还有一些支持了新的豆瓣说的推荐，优化了播放列表载入的策略。</p>
<p>另外值得highlight的是，对应的gnome-shell扩展发布了0.0.2版本，唯一的更新是专辑封面现在会显示在gnome-shell的菜单中。<br />
<img src="http://i.imgur.com/7Q1CP.jpg" alt="" /></p>
<p>你可以从github获得最新的插件和gnome-shell扩展：</p>
<ul>
<li>exaile-doubanfm-plugin 0.0.11-captcha: <a href="https://github.com/sunng87/exaile-doubanfm-plugin/downloads">https://github.com/sunng87/exaile-doubanfm-plugin/downloads</a></li>
<li>exaile-doubanfm-gnome-shell-extension 0.0.2: <a href="https://github.com/sunng87/exaile-doubanfm-gnome-shell-extension/tarball/0.0.2">https://github.com/sunng87/exaile-doubanfm-gnome-shell-extension/tarball/0.0.2</a></li>
<p>安装豆瓣电台插件请参考<a href="https://github.com/sunng87/exaile-doubanfm-plugin/wiki/Installation">这里</a>。gnome-shell扩展直接解压至~/.local/share/gnome-shell/extensions/即可
</ul>
<p>有任何问题都可以在github或这里留言。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/exaile%e8%b1%86%e7%93%a3%e7%94%b5%e5%8f%b0%e6%8f%92%e4%bb%b60-0-11%e5%8f%91%e5%b8%83/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

