<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-869230364755086797</id><updated>2012-01-26T17:53:06.930+08:00</updated><category term='rsh'/><category term='Bespin'/><category term='reading'/><category term='jQuery'/><category term='GWT'/><category term='scala'/><category term='javascript'/><category term='REST'/><category term='books'/><category term='ajax'/><category term='RestGWT'/><category term='google-appengine'/><category term='Hibernate'/><category term='NSMUQ'/><category term='lucene'/><category term='maven'/><category term='bnd'/><category term='RPC'/><category term='Apple'/><category term='django'/><category term='Groovy'/><category term='edgebox'/><category term='pdfbox'/><category term='photo'/><category term='osgi'/><category term='iPhone'/><category term='tika'/><category term='web-resources'/><category term='python'/><category term='FP'/><category term='Restlet'/><category term='DSL'/><category term='tips'/><category term='haskell'/><category term='Eclipse'/><category term='Grails'/><category term='E4'/><category term='木木'/><category term='Spring'/><category term='pypy'/><category term='file-icons'/><category term='google'/><title type='text'>The Beta Things</title><subtitle type='html'>about coding, life and all the beta things.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>51</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-6943406132249727164</id><published>2009-02-20T13:24:00.002+08:00</published><updated>2009-02-21T11:21:21.936+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='E4'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Bespin'/><title type='text'>E4 / Bespin</title><content type='html'>昨天还在闲聊的时候和同事聊到有关于Eclipse IDE in Web的话题，起因似乎关于Flex的能力和可能的应用场景。今天便发现有人已经开始行动，并且有所成果了。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://wiki.eclipse.org/E4/Bespin" target="_blank"&gt;E4/Bespin&lt;/a&gt;， 一个基于&lt;a href="https://wiki.mozilla.org/Labs/Bespin"&gt;Mozilla Lab&lt;/a&gt; &lt;a href="https://bespin.mozilla.com/"&gt;Bespin&lt;/a&gt;项目的扩展，已经可以玩玩了。&lt;br /&gt;&lt;br /&gt;我尝试着按照E4/Bespin页面上面的说明，安装如同小风吹一样顺畅。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-6943406132249727164?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/6943406132249727164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=6943406132249727164' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6943406132249727164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6943406132249727164'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2009/02/e4-bespin.html' title='E4 / Bespin'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-8259773691724337902</id><published>2008-12-26T13:37:00.008+08:00</published><updated>2009-05-15T22:01:25.304+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>foldl by foldr</title><content type='html'>&lt;a href="http://www.realworldhaskell.org/"&gt;RWH&lt;/a&gt;上在讲述 functional programming 中的fold的时候举了个例子，说foldl也可以由foldr来实现，具体的代码如下：&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;foldl :: (a-&gt;b-&gt;a)-&gt;a-&gt;[b]-&gt;a&lt;br /&gt;foldl f z xs = foldr step id xs z&lt;br /&gt; where step x g a = g (f  a x)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;开始总是没想明白，昨天才恍然大悟，具体的例子如下，&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;foldl (+) 0 [1,2,3] --&gt;&lt;br /&gt;foldr step id [1,2,3] 0 --&gt;&lt;br /&gt;step 1 (step 2 (step 3 id)) 0 --&gt;&lt;br /&gt;step 2 (step 3 id) (1 + 0) --&gt;&lt;br /&gt;step 3 id ((1+0)+2) --&gt;&lt;br /&gt;id (((1+0)+2)+3)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;特此记录一下，也算是脑子没白动。&lt;br /&gt;&lt;br /&gt;章节的后面有一个与之相关的练习，用&lt;code&gt;foldr&lt;/code&gt;实现&lt;code&gt;takeWhile&lt;/code&gt;，倒是一个很好的回顾。先试着用foldl来实现一把，毕竟takeWhile应该从左边开始计算。&lt;br /&gt;&lt;pre name="code"&gt;&lt;br /&gt;takeWhile_foldl :: (a-&gt;Bool)-&gt;[a]-&gt;[a]&lt;br /&gt;takeWhile_foldl p xs = head (foldl step [[]] xs)&lt;br /&gt;                     where step x y | p y = init x ++ [last x ++ [y]]&lt;br /&gt;                                    | otherwise = x ++ [[]]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;然后，根据上面给出的foldl的foldr解法得到下面的实现:&lt;br /&gt;&lt;pre name="code"&gt;&lt;br /&gt;takeWhile_foldr :: (a-&gt;Bool)-&gt;[a]-&gt;[a]&lt;br /&gt;takeWhile_foldr p xs = head (foldr step id xs [[]])&lt;br /&gt;                        where step x g a | p x = g (init a ++ [last a ++ [x]])&lt;br /&gt;                                         | otherwise = g (a ++ [[]])&lt;br /&gt;                                       &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-8259773691724337902?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/8259773691724337902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=8259773691724337902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8259773691724337902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8259773691724337902'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/foldl-by-foldr.html' title='foldl by foldr'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-538084403923565616</id><published>2008-12-25T11:35:00.003+08:00</published><updated>2008-12-25T13:50:08.943+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='FP'/><title type='text'>isSuffixOf in Haskell</title><content type='html'>&lt;code&gt;isSuffixOf&lt;/code&gt;是Haskell中的一个常见的List操作，因此也是&lt;code&gt;Prelude&lt;/code&gt;的一员。&lt;br /&gt;&lt;br /&gt;&lt;code&gt;isSuffixOf&lt;/code&gt;的功效类似于Java中&lt;code&gt;String.contains&lt;/code&gt;，只不过由于在Haskell中String就是一个List of Char，因此&lt;code&gt;isSuffixOf&lt;/code&gt;可以应用于更广泛的List而非String。&lt;br /&gt;&lt;br /&gt;在看RWH的时候，在尝试着使用现有的几个List函数来实现一下&lt;code&gt;isSuffixOf&lt;/code&gt;，凭着我已有的知识和习惯，给出了如下的代码：&lt;br /&gt;&lt;pre name="code"&gt;&lt;br /&gt;myisInfixOf :: (Eq a)=&gt;[a]-&gt;[a]-&gt;Bool&lt;br /&gt;myisInfixOf [] _ = True&lt;br /&gt;myisInfixOf _ [] = False&lt;br /&gt;myisInfixOf x y = let (pre, suf) = break (==(head x)) y&lt;br /&gt;               in if isPrefixOf x suf&lt;br /&gt;                  then True&lt;br /&gt;                  else case suf of&lt;br /&gt;                    [] -&gt; False&lt;br /&gt;                    otherwise -&gt; myisInfixOf x $ tail suf&lt;br /&gt;&lt;/pre&gt;为了表示和我传统的Imperative编成方式有所区别，我尝试了使用higher-order functions，pattern matching还有递归。然而，当我看到了GHC的标准库中的实现后，还是大吃一惊。可以和Java中的String.indexOf做一下比较。&lt;br /&gt;&lt;pre&gt;&lt;span class="definition"&gt;isInfixOf&lt;/span&gt;               &lt;span class="keyglyph"&gt;::&lt;/span&gt; &lt;span class="layout"&gt;(&lt;/span&gt;&lt;span class="conid"&gt;Eq&lt;/span&gt; &lt;span class="varid"&gt;a&lt;/span&gt;&lt;span class="layout"&gt;)&lt;/span&gt; &lt;span class="keyglyph"&gt;=&gt;&lt;/span&gt; &lt;span class="keyglyph"&gt;[&lt;/span&gt;&lt;span class="varid"&gt;a&lt;/span&gt;&lt;span class="keyglyph"&gt;]&lt;/span&gt; &lt;span class="keyglyph"&gt;-&gt;&lt;/span&gt; &lt;span class="keyglyph"&gt;[&lt;/span&gt;&lt;span class="varid"&gt;a&lt;/span&gt;&lt;span class="keyglyph"&gt;]&lt;/span&gt; &lt;span class="keyglyph"&gt;-&gt;&lt;/span&gt; &lt;span class="conid"&gt;Bool&lt;/span&gt;&lt;br /&gt;&lt;a name="line-303"&gt;&lt;/a&gt;&lt;span class="definition"&gt;isInfixOf&lt;/span&gt; &lt;span class="varid"&gt;needle&lt;/span&gt; &lt;span class="varid"&gt;haystack&lt;/span&gt; &lt;span class="keyglyph"&gt;=&lt;/span&gt; &lt;span class="varid"&gt;any&lt;/span&gt; &lt;span class="layout"&gt;(&lt;/span&gt;&lt;span class="varid"&gt;isPrefixOf&lt;/span&gt; &lt;span class="varid"&gt;needle&lt;/span&gt;&lt;span class="layout"&gt;)&lt;/span&gt; &lt;span class="layout"&gt;(&lt;/span&gt;&lt;span class="varid"&gt;tails&lt;/span&gt; &lt;span class="varid"&gt;haystack&lt;/span&gt;&lt;span class="layout"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;这个实现在一个tails序列中，寻找任意(any)一个元素，以needle开始。简洁明了，令人吃惊。最有趣的一个地方便是这个tails序列。它首先得到一个序列的tail，然后依次创建tail的tail。这样any查找才起作用。&lt;br /&gt;&lt;br /&gt;从时间性能上考虑，由于都是使用的最单纯的查找算法，上面几种没有多大的区别。从空间性能上考虑，感觉上当然Java的实现消耗最小。然而这种比较的意义有多大，却值得考虑。FP可以看作是相对于Imperative较高级的一种语言，其更关注于what to do，而非how to do。由于Lazy evaluation，这个tails序列并没分配想象中的那么多空间。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-538084403923565616?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/538084403923565616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=538084403923565616' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/538084403923565616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/538084403923565616'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/issuffixof-in-haskell.html' title='isSuffixOf in Haskell'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7257427011117466782</id><published>2008-12-22T13:36:00.003+08:00</published><updated>2008-12-22T16:28:46.589+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FP'/><title type='text'>PinS和RWH同时入围今年的Jolt</title><content type='html'>来自&lt;a href="http://lambda-the-ultimate.org/node/3134"&gt;LtU&lt;/a&gt;，&lt;a href="http://www.artima.com/shop/programming_in_scala"&gt;Programming in Scala&lt;/a&gt;和&lt;a href="http://www.realworldhaskell.org/"&gt;Real World Haskell&lt;/a&gt;同时入围今年的Jolt的&lt;a href="http://www.joltawards.com/finalists.html#bookstech"&gt;Book technical&lt;/a&gt;的最后评选名单。&lt;br /&gt;&lt;br /&gt;应该可以说明，越来越多的人开始重视functional programming语言了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7257427011117466782?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7257427011117466782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7257427011117466782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7257427011117466782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7257427011117466782'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/pinsrwhjolt.html' title='PinS和RWH同时入围今年的Jolt'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-4088001156401743723</id><published>2008-12-22T12:46:00.002+08:00</published><updated>2008-12-22T13:13:24.082+08:00</updated><title type='text'>书店</title><content type='html'>前些日子去淮海路，发现心仪的三联书店关了，那应该还是10月份的时候，取而代之的是不知道那家服装店，或是其他类似的东西。这家三联书店店面不大，因此并没有很多空间放置畅销书，教参，家庭百宝书，美容减肥指南等，因此常常会有惊喜。有一次买到过&lt;a href="http://en.wikipedia.org/wiki/Anthony_Bourdain"&gt;安东尼 伯尔顿&lt;/a&gt;这个"流氓"大厨的书。&lt;br /&gt;&lt;br /&gt;今天去龙之梦，发现龙强书屋门口的铁栅卷帘门也合的严严实实。原本安排的一天的计划，第一项就没能实践。龙强书店巨大，充斥了各种书籍，三联没有的它都有，并且有过之而无不及。正因为如此，也常常会有惊喜。其他地方找不到的书，往往躺在某个布满灰尘的角落里。&lt;br /&gt;&lt;br /&gt;其他的那些自以为有品位的书店，有个有品位的名字，搞些有品位的活动的那种，反而逛起来毫无乐趣可言。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-4088001156401743723?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/4088001156401743723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=4088001156401743723' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4088001156401743723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4088001156401743723'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/blog-post.html' title='书店'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-3175077052100185912</id><published>2008-12-20T11:12:00.003+08:00</published><updated>2008-12-20T12:24:31.209+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Haskell is lazy</title><content type='html'>昨天在做Programming Haskell上面的一道练习，脚踏实地的感受了一下Haskell的lazy evaluation得特性。&lt;br /&gt;&lt;br /&gt;题目很简单，给出了一个函数&lt;code&gt;unfold&lt;/code&gt;，定义如下&lt;br /&gt;&lt;pre name="code"&gt;&lt;br /&gt;unfold :: (b -&gt; Bool) -&gt; (b -&gt; a) -&gt; (b -&gt; b) -&gt; b -&gt; [a]&lt;br /&gt;unfold p h t x | p x = []&lt;br /&gt;            | otherwise = h x : unfold p h t (t x)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;unfold通过一个predicate p 来判x的值，如果为True则返回一个空List，否则的话递归计算unfold p h t (t x)，并且把h x的结果加在这个递归返回序列之前。&lt;br /&gt;也就是说，在通常意义下面，predicate p用来结束递归的那个重要的条件。&lt;br /&gt;&lt;br /&gt;要求是使用unfold来实现&lt;a href="http://www.zvon.org/other/haskell/Outputprelude/iterate_f.html"&gt;iterate f&lt;/a&gt;，(iterate 返回一个无限序列)。&lt;br /&gt;&lt;br /&gt;一个解答是&lt;br /&gt;&lt;pre name="code"&gt;&lt;br /&gt;iterate :: (a-&gt;a)-&gt;a-&gt;[a]&lt;br /&gt;iterate f = unfold nf id f&lt;br /&gt;                 where nf x = False&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;传统的命令式(imperative)程序员乍一看，便会指出一个显而易见的错误，递归的结束条件永远不为真，因为&lt;code&gt; nf x = False&lt;/code&gt;。然而这个判断，却在Haskell面前不成立，起码在当前的这个情况下，因为lazy的Haskell并不急匆匆的一定要找到递归的终止条件不可，才能完成计算。因为在很多情况下，这并非必要。比如，在GHCi下运行&lt;code&gt;take 8 &amp;amp; iterate (*2) 1&lt;/code&gt;，便会得到&lt;code&gt;[1,2,4,8,16,32,64]&lt;/code&gt;这样一个序列。 我只需要前8个元素，为什么一定要全计算完呢。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-3175077052100185912?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/3175077052100185912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=3175077052100185912' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3175077052100185912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3175077052100185912'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/haskell-is-lazy.html' title='Haskell is lazy'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-2144544548405796896</id><published>2008-12-10T15:02:00.003+08:00</published><updated>2009-05-15T22:04:10.510+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Merge Sort in Scala</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Merge_sort"&gt;Merge Sort&lt;/a&gt; is a kind of fast sorting algorithm with &lt;code&gt;O(nlog(n))&lt;/code&gt; order.&lt;br /&gt;&lt;br /&gt;Merge sort itself is a recursive algorithm and can be expressed neatly even in an &lt;a href="http://en.wikipedia.org/wiki/Imperative_programming"&gt;Imperative programming&lt;/a&gt; like &lt;a href="http://java.sun.com/products/jfc/tsc/articles/treetable1/src/MergeSort.java"&gt;Java&lt;/a&gt;. However pattern matching and high order functions in Scala can make this even interesting.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:scala"&gt;&lt;br /&gt;def mergeSort(list:List[Int]):List[Int] = list match {&lt;br /&gt; case x::Nil=&amp;gt; List(x)&lt;br /&gt; case _ =&amp;gt;&lt;br /&gt;   val (a, b) = list.splitAt(list.length /2)&lt;br /&gt;   merge(mergeSort(a), mergeSort(b))     &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def merge(aList:List[Int], bList:List[Int]):List[Int]= bList match {       &lt;br /&gt; case Nil =&amp;gt; aList&lt;br /&gt; case _ =&amp;gt;&lt;br /&gt;   aList match {&lt;br /&gt;   case Nil =&amp;gt; bList&lt;br /&gt;   case x::xs =&amp;gt;&lt;br /&gt;     if (x &amp;lt; bList.head)&lt;br /&gt;    x::merge(xs, bList)&lt;br /&gt;     else&lt;br /&gt;    bList.head::merge(aList, bList.tail)               &lt;br /&gt;   }   &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-2144544548405796896?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/2144544548405796896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=2144544548405796896' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/2144544548405796896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/2144544548405796896'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/merge-sort-in-scala.html' title='Merge Sort in Scala'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-2537920512465062904</id><published>2008-12-10T12:21:00.004+08:00</published><updated>2009-05-15T22:02:18.375+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Insertion Sort in Scala</title><content type='html'>Insertion sort is a so much simple and straightforward sorting algorithm. The pseudocode looks like following:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;for j ← 2 to length[A]&lt;br /&gt;    do key ← A[j]&lt;br /&gt;       i ← j - 1&lt;br /&gt;       while i &amp;gt; 0 and A[i] &amp;gt; key&lt;br /&gt;           do A[i + 1] ← A[i]&lt;br /&gt;              i ← i - 1&lt;br /&gt;       A[i + 1] ← key&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;But do it in Scala using FP is a quite interesting experience.&lt;br /&gt;&lt;br /&gt;Firstly, the traditional way in Scala:&lt;br /&gt;&lt;pre class="brush:scala"&gt;&lt;br /&gt;def insertSort(list:Array[Int]) = {     &lt;br /&gt; var j = 1&lt;br /&gt; while(j&amp;lt;list.length){   &lt;br /&gt;   val key = list(j)&lt;br /&gt;   var i = j-1&lt;br /&gt;   while(i&amp;gt;=0 &amp;amp;&amp;amp; list(i)&amp;gt;key){&lt;br /&gt;     list(i+1) = list(i)&lt;br /&gt;     i=i-1&lt;br /&gt;   }&lt;br /&gt;   list(i+1)=key&lt;br /&gt;   println("In the middle " + list.mkString(","))&lt;br /&gt;   j=j+1&lt;br /&gt; }&lt;br /&gt; list&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I use &lt;code&gt;while&lt;/code&gt; rather than &lt;code&gt;for&lt;/code&gt;, because &lt;code&gt;for&lt;/code&gt; means more than looping.&lt;br /&gt;&lt;br /&gt;The pure functional way requires no side-effect, which also generally means immutable and no loop.&lt;br /&gt;&lt;br /&gt;So the first function is &lt;code&gt;insert(list:List[Int], t:Int]:List[Int]&lt;/code&gt;, which inserts a value &lt;code&gt;t&lt;/code&gt; into a sorted list &lt;code&gt;list&lt;/code&gt; and returns the result.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def insert(list:List[Int], t:Int):List[Int]= list match {&lt;br /&gt;   case Nil =&amp;gt; List[Int](t)&lt;br /&gt;   case x::r if x &amp;gt; t=&amp;gt; t::x::r&lt;br /&gt;   case x::r =&amp;gt; x::insert(r,t)      &lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pattern match makes this like a breeze. &lt;br /&gt;&lt;br /&gt;Then the sorting function:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def insertSortFp(list:List[Int])={&lt;br /&gt;    (list :\ List[Int]())((a,b)=&amp;gt;insert(b,a))&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I use &lt;code&gt;foldRight&lt;/code&gt; here just because of my laziness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-2537920512465062904?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/2537920512465062904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=2537920512465062904' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/2537920512465062904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/2537920512465062904'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/insertion-sort-in-scala.html' title='Insertion Sort in Scala'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-4726222592457742745</id><published>2008-12-03T22:47:00.002+08:00</published><updated>2008-12-03T22:59:14.671+08:00</updated><title type='text'>Pandora Radio, the most downloaded free app on iPhone</title><content type='html'>又来自&lt;a href="http://www.guardian.co.uk/technology/blog/2008/dec/03/pandora-iphone"&gt;online&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;the most downloaded free application on Apple's iTunes 2008 list (sorry, it's not on the web) is Pandora Radio, the internet streaming radio service.&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;同样，在Pandora的&lt;a href="http://blog.pandora.com/pandora/archives/2008/12/2000000_pandora.html"&gt;Blog&lt;/a&gt;中，也在庆祝这一成就:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://blog.pandora.com/pandora/archives/images/2M%20iPhones.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer; width: 180px; height: 209px;" src="http://blog.pandora.com/pandora/archives/images/2M%20iPhones.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Pandora一直是我最爱的服务之一，只是似乎除了来自美国IP之外，其余国家一概由于法律/版权的原因不提供服务。我只能在办公室里满足一下。&lt;br /&gt;&lt;br /&gt;PS: iPhone今天被偷了，欲哭无泪。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-4726222592457742745?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/4726222592457742745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=4726222592457742745' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4726222592457742745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4726222592457742745'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/pandora-radio-most-downloaded-free-app.html' title='Pandora Radio, the most downloaded free app on iPhone'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-3279563089563273377</id><published>2008-12-01T21:51:00.002+08:00</published><updated>2008-12-01T21:55:16.113+08:00</updated><title type='text'>辛普森一家开始恶搞苹果(Apple)</title><content type='html'>&lt;a href="http://www.guardian.co.uk/technology/blog/2008/dec/01/apple-iphone-simpsons-satire"&gt;来自Online&lt;/a&gt;，在恶搞过Bush之后，辛普生一家盯上了Apple，最近的一期节目中便是：&lt;br /&gt;&lt;p&gt; &lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;"it's so sterile," gasps Lisa on seeing the new Mapple store in Springfield. (Well, they've opened everywhere else in the US, haven't they?) Bart then disses a "Steve Mobs" product announcement in front of a crowd of gaping nerds, "You think you're cool because you buy a $500 phone with a picture of a fruit on it. Well guess what? They cost 8 bucks to make and I pee on every one!" &lt;/p&gt;&lt;p&gt;A Mapple store employee then angrily responds, "Who dares question the boss we fired 10 years ago and then brought back!"&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;最后一句爆笑！！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-3279563089563273377?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/3279563089563273377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=3279563089563273377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3279563089563273377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3279563089563273377'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/12/apple.html' title='辛普森一家开始恶搞苹果(Apple)'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7131543739384149542</id><published>2008-11-30T12:21:00.002+08:00</published><updated>2008-11-30T12:28:39.088+08:00</updated><title type='text'>IBM patent: Pay at the table system</title><content type='html'>有一个来自IBM的古怪专利，&lt;span style="font-size:78%;"&gt;&lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&amp;amp;Sect2=HITOFF&amp;amp;d=PALL&amp;amp;p=1&amp;amp;u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&amp;amp;r=1&amp;amp;f=G&amp;amp;l=50&amp;amp;s1=7,457,767.PN.&amp;amp;OS=PN/7,457,767&amp;amp;RS=PN/7,457,767"&gt;Pay at the table system&lt;/a&gt;获得了美国专利局的&lt;a href="http://solidot.org/article.pl?sid=08/11/28/0641211"&gt;批准&lt;/a&gt;。&lt;br /&gt;&lt;/span&gt;&lt;blockquote&gt;Patrons at a restaurant or bar can pay at their table using credit cards,      without involving the restaurant or bar cashier and/or wait staff.      Patrons are assisted using this system in dividing the bill by displaying      the amount due (including tax) and allowing each patron to enter the      amount they wish to pay. When the initial bill is presented, a balance      due will be displayed and the indication will be provided that the bill      has yet to be paid in full. As each transaction is entered, a running      total will be displayed indicating the remaining balance due. When the      running total reaches zero, the bill is paid in full, and an indication      will be provided, such as by illuminating a green indicator light or by      displaying a balance due of $0.00. &lt;/blockquote&gt;可是，这样一来，the mighty &lt;a href="http://www.uz.ac.zw/science/maths/zimaths/bistro.htm"&gt;&lt;em&gt;Bistromathematical &lt;/em&gt; &lt;/a&gt;威力岂不是大减。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7131543739384149542?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7131543739384149542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7131543739384149542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7131543739384149542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7131543739384149542'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/ibm-patent-pay-at-table-system.html' title='IBM patent: Pay at the table system'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-5796504306473220621</id><published>2008-11-30T11:49:00.002+08:00</published><updated>2008-11-30T11:56:32.992+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Real World Haskell</title><content type='html'>很多人都很兴奋的提到说，受到了从&lt;a href="http://www.amazon.com/gp/product/0596514980?ie=UTF8&amp;amp;tag=reaworhas-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0596514980"&gt;Amazon&lt;/a&gt;寄来的&lt;a href="http://www.realworldhaskell.org/"&gt;Real World Haskell&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;其实我，好几天前就通过&lt;span style="font-style: italic;"&gt;非正规手段 &lt;/span&gt;（实在是辜负了大家的期望，很是对不起勤勤恳恳的作者，和辛辛苦苦的pre-reader），得到了chm版本。但是似乎最近还没有时间细读，惭愧惭愧。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-5796504306473220621?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/5796504306473220621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=5796504306473220621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5796504306473220621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5796504306473220621'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/real-world-haskell.html' title='Real World Haskell'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7969852810373213576</id><published>2008-11-24T22:27:00.005+08:00</published><updated>2008-11-24T23:04:05.211+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><title type='text'>GWT-ENT 看上去挺有趣</title><content type='html'>&lt;a href="http://code.google.com/p/gwt-ent/"&gt;GWT-Ent&lt;/a&gt;，&lt;span title="bring gwt to build enterprise program"&gt;一个旨在把GWT带向企业级应用的项目&lt;/span&gt;，最近在GWT maillist中宣布了一个很有的工具-&lt;a href="http://code.google.com/p/gwt-ent/wiki/AOP"&gt;GWT AOP&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;GWT AOP借鉴了AspectJ 5的annotation定义，实现了5个常用的Advice:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;@Around&lt;/li&gt;&lt;li&gt;@Before&lt;/li&gt;&lt;li&gt;@After&lt;/li&gt;&lt;li&gt; @AfterReturning&lt;/li&gt;&lt;li&gt;@AfterThrowing&lt;/li&gt;&lt;/ol&gt;至于Pointcut的描述，GWT AOP同时支持AspectJ的pointcut表达式和Google Guice的matchclass(我和Guice不熟)。&lt;br /&gt;&lt;br /&gt;我还没有想清楚GWT AOP能带来如何显著，壮观的效果，但是这的确是一个GWT generator的非常不错的用例。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7969852810373213576?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7969852810373213576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7969852810373213576' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7969852810373213576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7969852810373213576'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/gwt-ent.html' title='GWT-ENT 看上去挺有趣'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-6745302414308435999</id><published>2008-11-20T21:53:00.002+08:00</published><updated>2008-11-20T21:54:17.868+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google-appengine'/><title type='text'>Blog on AppEngine</title><content type='html'>I am thinking of writing a blog-like application using AppEngine, just for FUN!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-6745302414308435999?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/6745302414308435999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=6745302414308435999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6745302414308435999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6745302414308435999'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/blog-on-appengine.html' title='Blog on AppEngine'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-5229547126908557803</id><published>2008-11-19T23:24:00.001+08:00</published><updated>2008-11-20T10:34:26.866+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google-appengine'/><title type='text'>What is the next language of Google AppEngine</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://code.google.com/appengine/images/appengine_lowres.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 142px; height: 109px;" src="http://code.google.com/appengine/images/appengine_lowres.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;前些日子Google AppEngine公布了它短期的&lt;a href="http://code.google.com/appengine/docs/roadmap.html"&gt;Roadmap (to March 2009)&lt;/a&gt;，其中包括承诺增加一些服务。但我想，最令人值得期待的便是宣布会对新的Scripting language得支持。无数的猜测已经遍布网络了。 The most exciting item is about its plan for supporting new Scripting language. 无数的&lt;a href="http://neilbartlett.name/blog/2008/11/07/speculating-about-google-app-engine-20/"&gt;猜测&lt;/a&gt;&lt;a href="http://www.sitepoint.com/blogs/2008/10/25/google-reveals-app-engine-product-map/"&gt;已经&lt;/a&gt;&lt;a href="http://news.cnet.com/8301-17939_109-10074158-2.html"&gt;遍布&lt;/a&gt;&lt;a href="http://www.controlenter.in/2008/10/google-developer-day-bangalore-google-app-engine-to-support-java-android-sdk-release-on-oct-22/"&gt;网络&lt;/a&gt;了，我这里也来凑凑热闹。&lt;br /&gt;&lt;br /&gt;直到今日，在GAE的issue tracking list中有大概 &lt;a href="http://code.google.com/p/googleappengine/issues/list?can=2&amp;amp;q=component:Languages&amp;amp;colspec=ID%20Type%20Status%20Priority%20Stars%20Owner%20Summary%20Log%20Component"&gt;针对17种不同语言的需求&lt;/a&gt;。最多的五个依次是Java(JVM)，PHP，Perl和JavaScript，其他的还包括C#, Erlang, Pascal, 等。&lt;br /&gt;&lt;br /&gt;首先，我想说得是，我不认为这次会支持一个.NET语言，也不会是一个相对"小众"的语言，如Erlang，Lisp或是COBOL。始终，我认为这次会从那top five中选择。&lt;br /&gt;&lt;br /&gt;另外，我不太愿意看到会是Ruby。作为一个与Python有些相像，而且用户群体规模也相近的语言，对于Ruby的支持实在没有给GAE带来多大的亮点。当然Ruby可以是一个nice-to-have的需求。&lt;br /&gt;&lt;br /&gt;很早以前关于&lt;a href="http://brad.livejournal.com/2388824.html"&gt;GAE支持Perl&lt;/a&gt;的故事就已经沸沸扬扬。事实上一个&lt;a href="http://code.google.com/p/perl-appengine/"&gt;20% Google project&lt;/a&gt;也已经开始了相当长的一段时间了。 但至今似乎还相当的沉寂，而且最后的一次代码更新也已经是8月份的事了。&lt;br /&gt;&lt;br /&gt;PHP，我不熟悉，因此也很难发挥。个人认为PHP是一个web开发语言，而人们更多地认为GAE是一个与Amazon Cloud Service等同的服务，因此也许需要一种更丰富，全能的语言，至少在感觉上应该更丰富，全能一些。&lt;br /&gt;&lt;br /&gt;最后，只剩下Java(JVM)和JavaScript了。我当然对于Java得支持会感到非常的兴奋，或者说是对JVM得支持，这样可以用更丰富的方式来开发GAE引用，比如说Groovy, JRuby（赫赫，Ruby的支持解决了），Scala，甚至是Lisp。而且根据Java的安全机制，应该很容易创建出一个受限的沙盒来满足GAE的需求。在说Google还有一个众人皆知的秘密武器——&lt;a href="http://en.wikipedia.org/wiki/Dalvik_virtual_machine"&gt;Dalvik&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;但是，我觉得如果GAE支持JavaScript来进行开发的话，会是一个非常非常cool的亮点。如同Python一样，JavaScript也应该算是Google的半官方语言了吧，因此首先不缺乏任何积极参与者。而使得JavaScript在浏览器里与Service-side通吃，也隐隐约约有些许的趋势，比如说&lt;a href="http://appjet.com/"&gt;AppJet&lt;/a&gt;。Google也有自己的JavaScript引擎，也可以发挥发挥。&lt;br /&gt;&lt;br /&gt;因此，我押宝在Java，但是感情方面在JavaScript。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-5229547126908557803?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/5229547126908557803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=5229547126908557803' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5229547126908557803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5229547126908557803'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/what-is-next-language-of-google.html' title='What is the next language of Google AppEngine'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-8337889886408943408</id><published>2008-11-17T22:09:00.004+08:00</published><updated>2008-11-17T22:30:29.180+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google-appengine'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>Google AppEngine with Django 1.0 on Windows</title><content type='html'>I tried &lt;a href="http://code.google.com/appengine/"&gt;Google AppEngine&lt;/a&gt; with &lt;a href="http://www.djangoproject.com/"&gt;Django 1.0.1&lt;/a&gt; today together with that &lt;a href="http://code.google.com/p/google-app-engine-django/"&gt;gae-django-helper&lt;/a&gt; r64.  On my windows box, I got this error report:&lt;br /&gt;&lt;small&gt;&lt;span style="color: rgb(144, 144, 144);"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/small&gt;&lt;blockquote&gt;&lt;small&gt;&lt;span style="color: rgb(144, 144, 144);"&gt;&lt;strong&gt;source_file&lt;/strong&gt; = &lt;zipimporter&gt;, source_file.&lt;strong&gt;load_module&lt;/strong&gt; = &lt;built-in&gt;, &lt;strong&gt;submodule_fullname&lt;/strong&gt; = 'django.core.files.temp'&lt;/built-in&gt;&lt;/zipimporter&gt;&lt;/span&gt;&lt;/small&gt;&lt;br /&gt;&lt;code&gt;django.zip\django\core\files\temp.py&lt;/code&gt; in &lt;strong&gt;TemporaryFile&lt;/strong&gt;()&lt;br /&gt;&lt;strong&gt;&lt;type&gt;&lt;/type&gt;&lt;/strong&gt;: 'module' object has no attribute 'unlink'   &lt;/blockquote&gt;Fortunately, I found &lt;a href="http://code.google.com/p/rietveld/issues/detail?id=44"&gt;this patch&lt;/a&gt; on &lt;a href="http://code.google.com/p/rietveld/"&gt;rietveld &lt;/a&gt;issue list. So my workaround is simply add following two lines in the beginning of main.py which is provided by &lt;a href="http://code.google.com/p/google-app-engine-django/"&gt;gae-django-helper&lt;/a&gt;.&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;if os.name == 'nt':&lt;br /&gt; os.unlink = lambda: None&lt;br /&gt;&lt;/pre&gt;Because &lt;code&gt;os.unlink&lt;/code&gt; is only called when OS is windows, it is safe when running your application in app engine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-8337889886408943408?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/8337889886408943408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=8337889886408943408' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8337889886408943408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8337889886408943408'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/google-appengine-with-django-10-on.html' title='Google AppEngine with Django 1.0 on Windows'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-1402913504320229977</id><published>2008-11-16T21:58:00.002+08:00</published><updated>2008-11-16T22:00:38.186+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>An amazing jQuery Demo - Solar System</title><content type='html'>From &lt;a href="http://www.ongwt.com/post/2008/11/15/Solar-System-%3A-wanted-in-GWT"&gt;onGWT.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ongwt.com/public/WindowsLiveWriter_SolarSystemwantedinGWT_9BB2_image_thumb.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 319px; height: 221px;" src="http://www.ongwt.com/public/WindowsLiveWriter_SolarSystemwantedinGWT_9BB2_image_thumb.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-1402913504320229977?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/1402913504320229977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=1402913504320229977' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1402913504320229977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1402913504320229977'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/amazing-jquery-demo-solar-system.html' title='An amazing jQuery Demo - Solar System'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-1829893079562272353</id><published>2008-11-16T15:19:00.002+08:00</published><updated>2008-11-16T15:59:19.110+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven Builder Helper plugin really helpful</title><content type='html'>&lt;span style="font-weight: bold;"&gt;I think I am dumb&lt;/span&gt;, cause I just found out this amazingly helpful maven plugin, &lt;a href="http://mojo.codehaus.org/build-helper-maven-plugin/index.html"&gt;Builder Helper&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Why? Just take a look at goals its supports:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://mojo.codehaus.org/build-helper-maven-plugin/add-source-mojo.html"&gt;build-helper:add-source&lt;/a&gt;  Add more source directories to the POM.&lt;/li&gt;&lt;li&gt;&lt;a href="http://mojo.codehaus.org/build-helper-maven-plugin/add-test-source-mojo.html"&gt;build-helper:add-test-source&lt;/a&gt;  Add test source directories to the POM.&lt;/li&gt;&lt;li&gt;&lt;a href="http://mojo.codehaus.org/build-helper-maven-plugin/attach-artifact-mojo.html"&gt;build-helper:attach-artifact&lt;/a&gt;  Attach additional artifacts to be installed and deployed.&lt;/li&gt;&lt;li&gt;&lt;a href="http://mojo.codehaus.org/build-helper-maven-plugin/remove-project-artifact-mojo.html"&gt;build-helper:remove-project-artifact&lt;/a&gt;  Remove project's artifacts from local repository.&lt;/li&gt;&lt;li&gt;&lt;a href="http://mojo.codehaus.org/build-helper-maven-plugin/reserve-network-port-mojo.html"&gt;build-helper:reserve-network-port&lt;/a&gt;  Reserve a list of random and unused network ports.&lt;/li&gt;&lt;/ul&gt;The first two allows your maven project using additional directories other than 'main/java' or 'test/java' as your source directories. And these additional directories are involved into standard maven building process.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-1829893079562272353?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/1829893079562272353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=1829893079562272353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1829893079562272353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1829893079562272353'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/maven-builder-helper-plugin-really.html' title='Maven Builder Helper plugin really helpful'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-4114263327447419868</id><published>2008-11-12T23:50:00.000+08:00</published><updated>2008-11-12T23:50:00.264+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>GWT RPC from non-servlet-container - finally</title><content type='html'>Finally, I get to this part after the &lt;a href="http://betathings.blogspot.com/2008/10/gwt-rpc-from-non-servlet-container-1.html"&gt;first&lt;/a&gt; and &lt;a href="http://betathings.blogspot.com/2008/10/gwt-gwt-rpc-from-non-servlet-container.html"&gt;second&lt;/a&gt; rounds.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;GwtRpc&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;A Scala module(object) GwtRpc, is created for this RPC purpose, which defines three traits of interest:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;GwtRpcSpp&lt;/li&gt;&lt;li&gt;RpcService&lt;/li&gt;&lt;li&gt;SppHolder&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;code&gt;GwtRpcSpp&lt;/code&gt; is a simple trait extending GWT's &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/server/rpc/SerializationPolicyProvider.html"&gt;SerializationPolicyProvider&lt;/a&gt;, which declares an abstract method &lt;code&gt;getPolicyFileInputStream&lt;/code&gt;:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def getPolicyFileInputStream(moduleBaseUrl:String,&lt;br /&gt;strongName:String):Option[InputStream]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;code&gt;moduleBaseUrl&lt;/code&gt; and &lt;code&gt;stringName&lt;/code&gt; are two parameters carried by client request of GWT RPC. This method is supposed to be implemented to allow users to hook up their own logic about getting &lt;a href="http://code.google.com/webtoolkit/releases/release-notes-1.4.60.html#Release_Notes_1_4_59"&gt;serialize policy file&lt;/a&gt; generated by GWT RPC.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;RpcService&lt;/code&gt; is another simple trait which is supposed to be mixed into entities who is going to be the end-implementations of GWT RPC services.&lt;br /&gt;&lt;pre name="code" class="java"&gt;trait RpcService { this:SppHolder with RemoteService =&gt;&lt;br /&gt;&lt;br /&gt; def call(final in: =&gt; String)(handler: PartialFunction[CallResult, Unit])={&lt;br /&gt;   ...&lt;br /&gt; }&lt;br /&gt; ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Method call is the main entry of a &lt;code&gt;RpcService&lt;/code&gt; implementation, which takes two arguments.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;in - a Call-by-name string: the UTF-8 payload of an RPC request;&lt;/li&gt;&lt;li&gt;handler - a partial function which is provided by user to match the result of a call and write result back to response&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;code&gt;SppHolder&lt;/code&gt; is a container of &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/server/rpc/SerializationPolicyProvider.html"&gt;SerializationPolicyProvider&lt;/a&gt;. &lt;code&gt;RpcService&lt;/code&gt; declares it as a part of its self type annotation which sort of declares a &lt;a href="http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/"&gt;dependency&lt;/a&gt; to SppHolder, only the dependency needs to be fulfilled by its implementation.&lt;br /&gt;&lt;br /&gt;Actually, this GwtRpc module is container-independent. It can be used in any container which provides IO stream as abstraction of HTTP request.&lt;br /&gt;&lt;h3&gt;The Restlet implementation&lt;/h3&gt;Cause I (in this series) take more interesting in &lt;a href="http://betathings.blogspot.com/2008/10/gwt-gwt-rpc-from-non-servlet-container.html"&gt;serving GWT RPC via Restlet&lt;/a&gt;, I would give a simple implementation for &lt;a href="http://www.restlet.org/"&gt;Restlet &lt;/a&gt;environment.&lt;br /&gt;&lt;br /&gt;Generally, Restlet allows you to serve a HTTP request via a &lt;a href="http://www.restlet.org/documentation/1.1/api/org/restlet/Restlet.html"&gt;Restlet&lt;/a&gt; or a &lt;a href="http://www.restlet.org/documentation/1.1/api/org/restlet/resource/Resource.html"&gt;Resource&lt;/a&gt;. As a result, two traits implementations for each of them are provided respectively.&lt;br /&gt;&lt;br /&gt;For Restlet:&lt;br /&gt;&lt;pre name="code" class="java"&gt;trait RpcRestlet extends Restlet with RpcService with SppHolder{this:RemoteService=&gt;&lt;br /&gt; override def handle(req:Request, resp:Response){&lt;br /&gt;   req.getMethod match{&lt;br /&gt;     case Method.POST=&gt;&lt;br /&gt;       call(fromStream(req.getEntity.getStream))(writeRpcResult(resp))&lt;br /&gt;     case _ =&gt; // do nothing&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;For Resource:&lt;br /&gt;&lt;pre name="code" class="java"&gt;trait RpcResource extends Resource with RpcService with SppHolder{this:RemoteService=&gt;&lt;br /&gt; override def acceptRepresentation(rep: Representation){&lt;br /&gt;   call(fromStream(rep.getStream))(writeRpcResult(getResponse)) &lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;code&gt;fromStream&lt;/code&gt; is a method to read payload from an InputStream. This payload is simple a UTF-8 string and will be decoded to an instance of &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/server/rpc/RPCRequest.html"&gt;RpcRequest&lt;/a&gt; by GWT's &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/server/rpc/RPC.html#decodeRequest%28java.lang.String%29"&gt;RPC.decodeRequest(String)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;writeRpcResult&lt;/code&gt; is a functional variable, which takes  a Response as argument and returns a PartialFunction:&lt;br /&gt;&lt;pre name="code" class="java"&gt;val writeRpcResult: Response=&gt;PartialFunction[CallStatus, Unit] = {r=&gt;{&lt;br /&gt;  case CallSuc(msg)=&gt;&lt;br /&gt;    val rep = new StringRepresentation(msg, MediaType.APPLICATION_JSON)&lt;br /&gt;    rep.setCharacterSet(CharacterSet.UTF_8)&lt;br /&gt;    rep.setDownloadable(true)&lt;br /&gt;    rep.setDownloadName("attachment")&lt;br /&gt;    r.setEntity(rep)&lt;br /&gt;    r.setStatus(Status.SUCCESS_OK)&lt;br /&gt;  case CallFail(msg)=&gt;&lt;br /&gt;    r.setEntity(new StringRepresentation(msg, MediaType.TEXT_PLAIN))&lt;br /&gt;    r.setStatus(Status.SERVER_ERROR_INTERNAL)&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;To create an implementation of GWT RemoteService, just do almost same thing as in GWT but change the parent class to either one of above. For example:&lt;br /&gt;&lt;pre name="code" class="java"&gt;abstract class PingServiceImpl extends RpcRestlet with PingService with SppHolder{&lt;br /&gt;def ping(msg:String)={&lt;br /&gt;  "Pong-&gt; " + msg + "@" + new Date&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;code&gt;PingServiceImpl&lt;/code&gt; is still abstract, because its dependency to &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/server/rpc/SerializationPolicyProvider.html"&gt;SerializationPolicyProvider&lt;/a&gt; has not been fulfilled. To make thing simple, I reuse the App created in &lt;a href="http://betathings.blogspot.com/2008/10/gwt-gwt-rpc-from-non-servlet-container.html"&gt;last installment&lt;/a&gt; as the base and make it a &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/server/rpc/SerializationPolicyProvider.html"&gt;SerializationPolicyProvider&lt;/a&gt; for the whole Application scope.&lt;br /&gt;&lt;br /&gt;The implementation looks like following code, using &lt;a href="http://www.restlet.org/documentation/1.1/api/org/restlet/Directory.html"&gt;Directory&lt;/a&gt; &lt;code&gt;gwtDir&lt;/code&gt; is a lazy way here.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;class App extends Application with GwtApp with GwtRpcSpp{self=&gt;&lt;br /&gt;def getPolicyFileInputStream(moduleBaseUrl:String,&lt;br /&gt;                            strongName:String):Option[InputStream]={&lt;br /&gt;  val ref = new Reference(moduleBaseUrl)&lt;br /&gt;  val response = gwtDir.get(ref.getLastSegment+"/"+getPolicyFileName(strongName))&lt;br /&gt;  if(Status.SUCCESS_OK == response.getStatus)&lt;br /&gt;    Some(response.getEntity.getStream)&lt;br /&gt;  else&lt;br /&gt;    None&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Finally attach ping service to the router of this application and specify the SppHolder dependency:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;override def createRoot={&lt;br /&gt;//...&lt;br /&gt;r.attach("/ping", new PingServiceImpl{&lt;br /&gt; def provider = self&lt;br /&gt;})&lt;br /&gt;//...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;There is no need to change code of GWT client, just let ping service call endpoint http://localhost:8080/ping will done.&lt;br /&gt;&lt;br /&gt;For complete source code of this sample, see &lt;a href="http://edgebox.googlecode.com/svn/sandbox/gwt-restlet-demo/"&gt;http://edgebox.googlecode.com/svn/sandbox/gwt-restlet-demo/&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-4114263327447419868?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/4114263327447419868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=4114263327447419868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4114263327447419868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4114263327447419868'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/gwt-rpc-from-non-servlet-container.html' title='GWT RPC from non-servlet-container - finally'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7576636269008174869</id><published>2008-11-11T21:26:00.002+08:00</published><updated>2008-11-11T21:52:20.462+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>G2One join SpringSource</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.springsource.com/files/u5/SpringSource-Acquires.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 228px; height: 128px;" src="http://www.springsource.com/files/u5/SpringSource-Acquires.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.theregister.co.uk/2008/11/11/springsource_g21/"&gt;This is the biggest of today&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;在报道里，Rod说：&lt;br /&gt;&lt;blockquote&gt;SpringSource plans to integrate Grails with dm Server, the company's &lt;a target="_blank" href="http://www.osgi.org/About/Technology"&gt;OSGi&lt;/a&gt;-based open-source Java server that uses the Spring Framework and launched this year.&lt;/blockquote&gt;当然还包括&lt;br /&gt;&lt;blockquote&gt;Groovy would let enterprise programmers re-use their existing Java skills while Groovy programmers can tap underlying power of Java. Groovy is able to access Java class libraries and the Spring container, which is used in the dm Server and can run on the Java virtual machine (JVM).&lt;/blockquote&gt;&lt;br /&gt;首先是祝贺&lt;a href="http://g2one.com/"&gt;G2One&lt;/a&gt;，当然还有&lt;a href="http://blog.springsource.com/2008/11/11/more-weapons-for-the-war-on-complexity-springsource-acquires-groovygrails-leader/"&gt;Guillaume LaForge&lt;/a&gt;和&lt;a href="http://graemerocher.blogspot.com/2008/11/groovy-and-grails-join-spring-family.html"&gt;Graeme Rocher&lt;/a&gt;。当然，两个人都看到了这次收购对于Groovy和Grails的好的一面，两个人都提到Eclipse IDE得支持。应该可以这么猜测，不久会有一个相当不错的Groovy和Grails Eclipse IDE（应该来自Spring的IDE team)。&lt;br /&gt;&lt;br /&gt;其他么，大家都重视不免有些担心这次收购会对这两个Java Open Community的明星项目略微担心，毕竟前些日子SpringSource的&lt;a href="http://www.jroller.com/habuma/entry/what_the_new_springsource_maintenance"&gt;&lt;/a&gt;&lt;a href="http://www.springsource.com/products/enterprise/maintenancepolicy"&gt;maintainence policy&lt;/a&gt;风波&lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=51078"&gt;还未&lt;/a&gt;&lt;a href="http://blog.springsource.com/2008/10/07/a-question-of-balance-tuning-the-maintenance-policy/"&gt;完全&lt;/a&gt;的&lt;a href="http://www.javaworld.com/community/?q=node/1367"&gt;平息&lt;/a&gt;。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7576636269008174869?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7576636269008174869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7576636269008174869' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7576636269008174869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7576636269008174869'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/g2one-join-springsource.html' title='G2One join SpringSource'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-5601616080179318175</id><published>2008-11-08T15:49:00.003+08:00</published><updated>2008-11-08T15:56:33.544+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='edgebox'/><category scheme='http://www.blogger.com/atom/ns#' term='RestGWT'/><title type='text'>Release RestGWT 0.0.1 snapshot</title><content type='html'>The first snapshot of &lt;a href="http://betathings.blogspot.com/2008/11/generate-requestbuilder-logic-using.html"&gt;RestGWT&lt;/a&gt; 0.0.1 is &lt;a href="http://code.google.com/p/edgebox/wiki/RestRemote"&gt;released&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-5601616080179318175?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/5601616080179318175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=5601616080179318175' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5601616080179318175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5601616080179318175'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/release-restgwt-001-snapshot.html' title='Release RestGWT 0.0.1 snapshot'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-8172135879817762462</id><published>2008-11-07T11:41:00.001+08:00</published><updated>2008-11-07T11:54:15.247+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NSMUQ'/><title type='text'>What is NSMUQ?</title><content type='html'>NSMUQ stands for &lt;span style="font-style: italic;"&gt;not-so-much-ultimate question.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-8172135879817762462?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/8172135879817762462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=8172135879817762462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8172135879817762462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8172135879817762462'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/what-is-nsmuq.html' title='What is NSMUQ?'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-8971108976179597817</id><published>2008-11-06T14:10:00.000+08:00</published><updated>2008-11-06T14:12:08.550+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='edgebox'/><title type='text'>Generate RequestBuilder logic using RestGWT</title><content type='html'>Besides GWT's &lt;a href="http://code.google.com/docreader/#p=google-web-toolkit-doc-1-5&amp;amp;s=google-web-toolkit-doc-1-5&amp;amp;t=DevGuideRemoteProcedureCalls"&gt;RPC&lt;/a&gt;, GWT also allows user to communicate backend web services using standard &lt;a href="http://code.google.com/docreader/#p=google-web-toolkit-doc-1-5&amp;amp;s=google-web-toolkit-doc-1-5&amp;amp;t=DevGuideHttp"&gt;HTTP calls&lt;/a&gt;. The latter, comparing with RPC, is much more flexible and supports arbitry payload formats.&lt;br /&gt;&lt;br /&gt;However, coding with GWT HTTP calls (the &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/http/client/RequestBuilder.html"&gt;RequestBuilder&lt;/a&gt;) is a redundant and repeating work. Besides worrying about preparing the payload content, developers also need to write lots of lines of code to prepare the instance of RequestBuilder itself, to worry about metadata (http headers) used for it, to care of the URL of &lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5"&gt;interface&lt;/a&gt; and the method of the HTTP call.&lt;br /&gt;&lt;br /&gt;This does not sound too much a big deal if the backend service is sort of traditional RPC style, in which the interface (the URL) of endpoint is usually fixed and these metadata used by HTTP calls are usually unchanged. For a RESTful style service, things might become a lit more complex, in which&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Each resource is unique identified by a URI;&lt;/li&gt;&lt;li&gt;Same kind of resources' URIs conforms to same pattern;&lt;/li&gt;&lt;li&gt;Metadata such as HTTP headers usually instruct how the backend service to process this request and impact the &lt;span style="font-style: italic;"&gt;representation &lt;/span&gt;of the response;&lt;/li&gt;&lt;/ul&gt;A bit helter-skelter, isn't it?&lt;br /&gt;&lt;h3&gt;Present you RestGWT, the generator for RequestBuilder logic&lt;/h3&gt;RestGWT is a &lt;a href="http://code.google.com/docreader/#p=google-web-toolkit-doc-1-5&amp;amp;s=google-web-toolkit-doc-1-5&amp;amp;t=DevGuideDeferredBindingGenerators"&gt;GWT generator&lt;/a&gt; implementation, particular for  simplifying coding work about GWT HTTP Calls,  specifically, HTTP Calls to a RESTful service.&lt;br /&gt;&lt;br /&gt;RestGWT steals some concepts and nice ideas from &lt;a href="http://jcp.org/en/jsr/detail?id=311"&gt;JAX-RS&lt;/a&gt;, &lt;a href="https://wadl.dev.java.net/"&gt;WADL&lt;/a&gt; and &lt;a href="http://www.restlet.org/"&gt;Restlet&lt;/a&gt;, says for making a HTTP Calls you will need&lt;br /&gt;&lt;ul&gt;&lt;li&gt;An &lt;code&gt;@Endpoint&lt;/code&gt; which specifies the uri template in the Restlet style, i.e. &lt;code&gt;/ci/{type}/{id}&lt;/code&gt; and the method used to do the call&lt;br /&gt;&lt;/li&gt;&lt;li&gt;One or more &lt;code&gt;@HttpHeader&lt;/code&gt;s indicates metadata, i.e &lt;code&gt;@HttpHeader(name="Content-Type", value="application/ci+xml)"&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Apply above two items on a method of an interface, i.e. &lt;code&gt;void getCI(String type, String id, RequestCallback callback);&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;@UriPart&lt;/code&gt; can be used to indicate how to replace url template with values specified by method parameters, so the method signature now becomes &lt;code&gt;void getCI(@UriPart("type") String type, @UriPart("id") String id);&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Finally, the interface containing the method needs extends interface &lt;code&gt;org.edgebox.gwt.rest.client.RestRemote&lt;/code&gt; as a flag;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Up-to-now, an endpoint to do a HTTP Call is declared as&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public interface MyService extends RestRemote{&lt;br /&gt;&lt;br /&gt;@Endpoint(method=RestGWT.Method.Represnt, urlTemplate="/a/ci/{type}/{id}")&lt;br /&gt;@HttpHeader(name="Content-Type", value="application/ci+xml")&lt;br /&gt;public void getCI(@UrlPart("type") String type,&lt;br /&gt;                  @UrlPart("id") String id, RequestCallback, callback);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now, to use this service, using GWT RPC style:&lt;br /&gt;&lt;pre name="code" class="java"&gt;MyService service = GWT.create(MyService.class)&lt;br /&gt;RequestCallback callback = //...&lt;br /&gt;service.getCI("person", "111",  callback)&lt;br /&gt;&lt;/pre&gt;Is this a nice cool idea? I am not quite sure, but at least it suits my requirement pretty well. At current moment, RestGWT is still under heavy working. But you can get source code from &lt;code&gt;http://edgebox.googlecode.com/svn/trunk/edgebox-restgwt&lt;/code&gt; for a look.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-8971108976179597817?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/8971108976179597817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=8971108976179597817' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8971108976179597817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8971108976179597817'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/generate-requestbuilder-logic-using.html' title='Generate RequestBuilder logic using RestGWT'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-4148721889327108657</id><published>2008-11-06T11:50:00.002+08:00</published><updated>2008-11-06T11:54:57.372+08:00</updated><title type='text'>Linkedin也裁员了</title><content type='html'>我最喜欢的一个Social network site - &lt;a href="http://www.linkedin.com"&gt;Linkedin&lt;/a&gt; - 最近也&lt;a href="http://tech.yahoo.com/news/cnet/20081106/tc_cnet/8301102331008340293"&gt;宣布裁员&lt;/a&gt;了，虽说人数只有区区的36人，但是却占据整个员工数目的10%。&lt;br /&gt;&lt;br /&gt;报道上还提到了有趣的一点：&lt;br /&gt;&lt;blockquote&gt;The site, which claims about 30 million members, is small in comparison with social-networking sites &lt;span class="yshortcuts" id="lw_1225943513_6"&gt;Facebook&lt;/span&gt; and &lt;span class="yshortcuts" id="lw_1225943513_7"&gt;MySpace&lt;/span&gt;. But the average LinkedIn member is 41 years old and earns about $110,000 a year.   &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-4148721889327108657?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/4148721889327108657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=4148721889327108657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4148721889327108657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4148721889327108657'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/linkedin.html' title='Linkedin也裁员了'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-5922735163600009518</id><published>2008-11-01T22:04:00.002+08:00</published><updated>2008-11-01T23:12:33.507+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='木木'/><title type='text'>木木听音乐</title><content type='html'>木木已经半个月大了。&lt;br /&gt;&lt;br /&gt;自从木木从医院搬回家，几乎每天晚上吃完晚饭之后，有个固定的节目用来帮助大家的消化。这便是听音乐，大约一小时左右。&lt;br /&gt;&lt;br /&gt;音乐的来源是我的爱婆(iPod)，在木妈的睡房里加上一对小音箱，便大功告成。由于许久没有往爱婆里面添加新歌，因此里面翻来覆去的就是那两千多首艇的烂熟的老歌，因此选择其来到也容易。&lt;br /&gt;&lt;br /&gt;首先，Nirvana, Sex Pistol, Ramones, Clash等处世风格较为激烈的Punk不会让木木现在听，毕竟anti-everything之类的教育现在还太早。The doors，Velvet underground，KoRn等较为阴郁的，或者以凡旋律为主的乐队也不再选择之列，起码现在不行。&lt;br /&gt;&lt;br /&gt;这样一来，在我可怜的list中，首选的是一些以旋律著称的乐手，一些folk，一些偏好电子的，一些键盘为主的，一些喜爱添加弦乐的，一些轻迷幻的，一些Brit Pop(很有趣)，一些Alter Punk(更有趣)。&lt;br /&gt;&lt;br /&gt;每天的开始曲目必然是&lt;a href="http://en.wikipedia.org/wiki/Belle_and_Sebastian"&gt;Belle &amp;amp; Sebastian&lt;/a&gt;的Fiction，这也是木妈在怀孕是后的最爱。在优美的钢琴solo进行到一半时，沁入如同干净的雪天中的突然传来腊梅香气一般的小提琴。&lt;br /&gt;&lt;br /&gt;然后，随机的，会有其他的一些&lt;a href="http://en.wikipedia.org/wiki/Belle_and_Sebastian"&gt;Belle &amp;amp; Sebastian&lt;/a&gt;，如Fox in the snow，一些&lt;a href="http://en.wikipedia.org/wiki/The_Divine_Comedy_%28band%29"&gt;The Divine Comedy&lt;/a&gt;，一些&lt;a href="http://en.wikipedia.org/wiki/Arabacus_Pulp"&gt;Pulp&lt;/a&gt;，一些&lt;a href="http://en.wikipedia.org/wiki/The_Verve"&gt;The Verve&lt;/a&gt;，一些&lt;a href="http://en.wikipedia.org/wiki/Tori_Amos"&gt;Tori Amos&lt;/a&gt;，一些早期的&lt;a href="http://en.wikipedia.org/wiki/Radiohead"&gt;Radiohead&lt;/a&gt;（如Nice Dream，Fake Plastic Trees, No Suprise等）， 一些&lt;a href="http://en.wikipedia.org/wiki/Sonic_Youth"&gt;Sonic Youth&lt;/a&gt;，诸如此类。&lt;br /&gt;&lt;br /&gt;木爸的个人感觉如下，木木比较喜欢频率比较高的声调，如钢琴，小提琴之类；不太喜欢Base和鼓为主的歌；比较喜欢舒缓的节奏；不太喜欢较为激烈的。Lady of certain age和Silence of these years似乎根容易让木木集中注意力，让木木平静。&lt;br /&gt;&lt;br /&gt;当然，这一切也很有可能是木爸的一厢情愿，也许木木完全是凭个人意愿，当时心情，随意发飚。不过，其他有余木爸相似爱婆list的父母们，也许也可以试试看。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-5922735163600009518?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/5922735163600009518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=5922735163600009518' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5922735163600009518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5922735163600009518'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/11/blog-post.html' title='木木听音乐'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-8294361496776742876</id><published>2008-10-31T13:18:00.002+08:00</published><updated>2008-11-10T17:33:49.631+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>GWT RPC from non-servlet-container (2)</title><content type='html'>In the second &lt;a href="http://betathings.blogspot.com/2008/10/gwt-rpc-from-non-servlet-container-1.html"&gt;post&lt;/a&gt;, I would like to show-off the project structure of a simple GWT application served by pure Restlet (&lt;span style="font-style: italic;"&gt;which means not running in a servlet container&lt;/span&gt;) Application as a sample and basis of further discussion.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The GWT Client&lt;/h3&gt;&lt;br /&gt;In order to deploy a GWT application in non-servlet container like Restlet, I can not package the GWT client in a &lt;a href="http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/WebComponents3.html"&gt;war&lt;/a&gt;. I choose to package everything (class files, java sources, gwt compiled js and other static resources) into a single jar. &lt;span style="font-style: italic;"&gt;It might be also friend to OSGi environment&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I use&lt;a href="http://code.google.com/p/gwt-maven/"&gt; gwt-maven plugin&lt;/a&gt; as the build tool, which is quite handy in our case. For detail usage of gwt-maven plugin, please check the &lt;a href="http://gwt-maven.googlecode.com/svn/docs/maven-googlewebtoolkit2-plugin/examples.html"&gt;example&lt;/a&gt;. I made some modification in order to create this "special" jar.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt; &amp;lt;groupId&amp;gt;com.totsp.gwt&amp;lt;/groupId&amp;gt;&lt;br /&gt; &amp;lt;artifactId&amp;gt;maven-googlewebtoolkit2-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt; &amp;lt;version&amp;gt;2.0-beta24&amp;lt;/version&amp;gt;&lt;br /&gt; &amp;lt;configuration&amp;gt;&lt;br /&gt;   ...&lt;br /&gt;   &amp;lt;output&amp;gt;${project.build.directory}/classes/_gwt&amp;lt;/output&amp;gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I changed the output directory of GWT resources, so that they can easily get packaged by maven jar plugin.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt; &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt; &amp;lt;artifactId&amp;gt;maven-jar-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt; &amp;lt;executions&amp;gt;&lt;br /&gt;   &amp;lt;execution&amp;gt;&lt;br /&gt;     &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;&lt;br /&gt;     &amp;lt;goals&amp;gt;&lt;br /&gt;       &amp;lt;goal&amp;gt;jar&amp;lt;/goal&amp;gt;&lt;br /&gt;     &amp;lt;/goals&amp;gt;&lt;br /&gt;     &amp;lt;configuration&amp;gt;&lt;br /&gt;       &amp;lt;classifier&amp;gt;gwt&amp;lt;/classifier&amp;gt;&lt;br /&gt;       &amp;lt;excludes&amp;gt;&lt;br /&gt;         &amp;lt;exclude&amp;gt;_gwt/.gwt-tmp/**&amp;lt;/exclude&amp;gt;&lt;br /&gt;       &amp;lt;/excludes&amp;gt;&lt;br /&gt;     &amp;lt;/configuration&amp;gt;&lt;br /&gt;   &amp;lt;/execution&amp;gt;&lt;br /&gt; &amp;lt;/executions&amp;gt;&lt;br /&gt; &amp;lt;configuration&amp;gt;&lt;br /&gt;   &amp;lt;excludes&amp;gt;&lt;br /&gt;     &amp;lt;exclude&amp;gt;_gwt/**&amp;lt;/exclude&amp;gt;&lt;br /&gt;   &amp;lt;/excludes&amp;gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Two jars are created, one with classifier "gwt" includes all static resources.&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;build&amp;gt;&lt;br /&gt;&amp;lt;resources&amp;gt;&lt;br /&gt;&amp;lt;resource&amp;gt;&lt;br /&gt;&amp;lt;directory&amp;gt;./src/main/java&amp;lt;/directory&amp;gt;&lt;br /&gt;&amp;lt;/resource&amp;gt;&lt;br /&gt;&amp;lt;resource&amp;gt;&lt;br /&gt;&amp;lt;directory&amp;gt;./src/main/resources&amp;lt;/directory&amp;gt;&lt;br /&gt;&amp;lt;/resource&amp;gt;&lt;br /&gt;&amp;lt;/resources&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;/build&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is a small trick to package java sources into GWT jar.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Restlet Application&lt;/h3&gt;&lt;span style="font-style: italic;"&gt;(Sorry for using Scala as the example language, but hopefully you will see how Scala can ease the development)&lt;/span&gt;&lt;br /&gt;At current moment, there is no standard way to deploy a web application using Restlet. Basically in Restlet, you expose dynamic part as a &lt;a href="http://www.restlet.org/documentation/1.1/api/org/restlet/resource/Resource.html"&gt;Resource&lt;/a&gt;, and serve static things using &lt;a href="http://www.restlet.org/documentation/1.1/api/org/restlet/Directory.html"&gt;Directory&lt;/a&gt; (see &lt;a href="http://www.restlet.org/documentation/1.1/tutorial#part06"&gt;example&lt;/a&gt; on Restlet site).&lt;br /&gt;&lt;br /&gt;I create a GwtApp trait for serving GWT client an &lt;a href="http://www.restlet.org/documentation/1.1/api/org/restlet/Application.html"&gt;Application&lt;/a&gt; scope.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;trait GwtApp extends Application{&lt;br /&gt; val gwtDir = new Directory(null, "clap://class/_gwt/")&lt;br /&gt;&lt;br /&gt; abstract override def createRoot():Restlet={&lt;br /&gt;   gwtDir.setContext(getContext)&lt;br /&gt;   super.createRoot match{&lt;br /&gt;     case root:Router=&gt;&lt;br /&gt;       root.attach("/_gwt", gwtDir);root&lt;br /&gt;     case r@_=&gt;&lt;br /&gt;       val root = new Router&lt;br /&gt;       root.attachDefault(r)&lt;br /&gt;       root.attach("/_gwt",gwtDir)&lt;br /&gt;       root&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The small "abstract override" trick creates a kind of AOP around aspect over &lt;code&gt;createRoot&lt;/code&gt; method, see &lt;a href="http://jonasboner.com/2008/02/06/aop-style-mixin-composition-stacks-in-scala/"&gt;this&lt;/a&gt;. So I can just mixin this trait into my application without any change.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;class App extends Application with GwtApp{&lt;br /&gt;&lt;br /&gt; override def createRoot():Restlet={&lt;br /&gt;   val r = // ... get Root as a Router&lt;br /&gt;   r.attach("/test", classOf[TestResource])&lt;br /&gt;   //attach the main view&lt;br /&gt;   r.attach("/main", new Restlet(getContext){&lt;br /&gt;     override def handle(req:Request, resp:Response){&lt;br /&gt;       val r = new InputRepresentation(&lt;br /&gt;       getClass.getResourceAsStream("/host.html"),&lt;br /&gt;         MediaType.TEXT_HTML)&lt;br /&gt;       resp.setEntity(r)&lt;br /&gt;     }                  &lt;br /&gt;   })&lt;br /&gt;   r&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Two endpoints are exposed by this application.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/main&lt;/code&gt; - return the host page of above GWT client, the src location of GWT bootstrap js file is &lt;code&gt;/_gwt/gr.demo.App/gr.demo.App.nocache.js&lt;/code&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/test&lt;/code&gt; - a very simple restful service accepting &lt;code&gt;text/html&lt;/code&gt; request and serving back a &lt;code&gt;text/plain&lt;/code&gt; representation, see below;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;class TestResource(ctx:Context, req:Request, resp:Response)&lt;br /&gt;   extends Resource(ctx,req,resp){&lt;br /&gt;&lt;br /&gt; getVariants.add(new Variant(MediaType.TEXT_HTML))&lt;br /&gt; override def represent(v:Variant)={&lt;br /&gt;   new StringRepresentation("Helo@"+new Date, MediaType.TEXT_PLAIN);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After you package all of above into a Component;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;val com = new Component&lt;br /&gt;Array(HTTP, FILE, CLAP).foreach(x=&gt;com.getClients.add(x))&lt;br /&gt;com.getServers.add(HTTP, 8080)&lt;br /&gt;com.getDefaultHost.attachDefault(new App)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You get a client served by pure Restlet application.&lt;br /&gt;&lt;br /&gt;So next post of this series will be the prototype of serving GWT RPC using Restlet, hopeful it will be cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-8294361496776742876?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/8294361496776742876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=8294361496776742876' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8294361496776742876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8294361496776742876'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/gwt-gwt-rpc-from-non-servlet-container.html' title='GWT RPC from non-servlet-container (2)'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7920684227158231376</id><published>2008-10-30T23:42:00.003+08:00</published><updated>2008-10-30T23:50:07.788+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala 2.7.2-RC5</title><content type='html'>今天下午才升级到了&lt;a href="http://www.scala-lang.org/node/340"&gt;Scala 2.7.2-RC4&lt;/a&gt;，没想到Scala team以迅雷不及掩耳之势，今天发布了&lt;a href="http://www.scala-lang.org/node/341"&gt;2.7.2的RC5&lt;/a&gt;。根据Scala-lang主页上的说明，感觉这应该是2.7.2正式release之前的最后一个RC了。&lt;br /&gt;&lt;blockquote&gt;We are taking particular care in polishing Scala 2.7.2, also considering that 2.7.2 will be the reference release for the "Programming in Scala" book, currently in print. This RC5 should really be our last release candidate for this release cycle, and should be shortly followed by the final release.&lt;/blockquote&gt;不过到现在，scala-tool的maven repository中，还没有rc4和rc5的版本。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7920684227158231376?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7920684227158231376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7920684227158231376' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7920684227158231376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7920684227158231376'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/scala-272-rc5.html' title='Scala 2.7.2-RC5'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-1560167642357544171</id><published>2008-10-30T13:49:00.003+08:00</published><updated>2008-10-30T15:30:02.794+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><title type='text'>Restlet-GWT, the compiled size</title><content type='html'>As mentioned in my &lt;a href="http://betathings.blogspot.com/2008/10/restlet-110-released.html"&gt;previous post&lt;/a&gt;, I would like to check the code size generated by GWT if Restlet-GWT is used. So here are two code snippets.&lt;br /&gt;&lt;br /&gt;&lt;fieldset&gt;&lt;legend&gt;The RequestBuilder from GWT core&lt;/legend&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;final RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, URL&lt;br /&gt;   .encode("http://localhost:8080/test"));&lt;br /&gt;Button b = new Button("Click me");&lt;br /&gt;RootPanel.get().add(b);&lt;br /&gt;b.addClickListener(new ClickListener() {&lt;br /&gt;&lt;br /&gt;public void onClick(Widget sender) {&lt;br /&gt;try {&lt;br /&gt;rb.sendRequest(null, new RequestCallback() {&lt;br /&gt;&lt;br /&gt;   public void onError(Request request, Throwable exception) {&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void onResponseReceived(Request request,&lt;br /&gt;           Response response) {&lt;br /&gt;       RootPanel.get().add(new Label(response.getText()));&lt;br /&gt;   }&lt;br /&gt;});&lt;br /&gt;} catch (RequestException e) {&lt;br /&gt;e.printStackTrace();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;/fieldset&gt;&lt;br /&gt;&lt;br /&gt;&lt;fieldset&gt;&lt;legend&gt;The code using Restlet-GWT&lt;/legend&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;final Client client = new Client(Protocol.HTTP);&lt;br /&gt;&lt;br /&gt;Button b = new Button("Click me");&lt;br /&gt;RootPanel.get().add(b);&lt;br /&gt;b.addClickListener(new ClickListener() {&lt;br /&gt;&lt;br /&gt;public void onClick(Widget sender) {&lt;br /&gt;client.get("http://localhost:8080/test", new Callback() {&lt;br /&gt;  public void onEvent(Request request, Response response) {&lt;br /&gt;      RootPanel.get().add(&lt;br /&gt;              new Label(response.getEntity().getText()));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/fieldset&gt;&lt;br /&gt;&lt;br /&gt;The obf style code size are (not gziped):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;For pure GWT, the size is around 30K;&lt;/li&gt;&lt;li&gt;For Restlet-GWT, the size is around 135K;&lt;/li&gt;&lt;/ul&gt;Is 100K difference big deal?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-1560167642357544171?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/1560167642357544171/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=1560167642357544171' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1560167642357544171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1560167642357544171'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/restlet-gwt-compiled-size.html' title='Restlet-GWT, the compiled size'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-1600615592890535082</id><published>2008-10-30T12:04:00.003+08:00</published><updated>2008-10-30T13:48:46.271+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><title type='text'>Restlet 1.1.0 released</title><content type='html'>Got notification from &lt;a href="http://blog.noelios.com"&gt;&lt;em class="info"&gt;Jerome Louvel&lt;/em&gt;&lt;/a&gt; on Linkedin, that &lt;a href="http://blog.noelios.com/2008/10/28/restlet-110-released/"&gt;Restlet 1.1.0 was officially released&lt;/a&gt; on 28 th, Oct. You can check detail what's-new there.&lt;br /&gt;&lt;br /&gt;The new &lt;a href="http://wiki.restlet.org/docs_1.1/13-restlet/144-restlet.html"&gt;Restlet-GWT&lt;/a&gt; module interests me most. Thanks to the &lt;a href="http://code.google.com/docreader/#p=google-web-toolkit-doc-1-5&amp;amp;s=google-web-toolkit-doc-1-5&amp;amp;t=ReleaseNotes_1_5_ImportantNotes"&gt;GWT 1.5's support of Java 5 syntax&lt;/a&gt;, so by using this new Restlet-GWT, you can almost seamlessly create a restful client for both browser and normal application by using one set of code. Which means you can create only one client API for your restful application/services (what ever) and says hey this is the client of my RIA, you can use it in your GWT client which runs inside browser or use it in your Eclipse RCP client.&lt;br /&gt;&lt;br /&gt;I have to say I haven't tried it yet. I am wondering whether it would be too heavy for a web application.&lt;br /&gt;&lt;br /&gt;From the programming model perspective, there is no big difference between Restlet-GWT with GWT's own &lt;a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/http/client/RequestBuilder.html"&gt;RequestBuilder&lt;/a&gt;. For pure GWT, you need to deal with plain text for both of request and response. For Restlet-GWT, there is a abstraction called Representation.&lt;br /&gt;&lt;br /&gt;Both of them require a callback object to receive responses. One advantage is that Restlet's response is content type aware (&lt;a href="http://wiki.restlet.org/docs_1.1/13-restlet/144-restlet/190-restlet.html"&gt;json&lt;/a&gt;, &lt;a href="http://wiki.restlet.org/docs_1.1/13-restlet/144-restlet/191-restlet.html"&gt;xml&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-1600615592890535082?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/1600615592890535082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=1600615592890535082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1600615592890535082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1600615592890535082'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/restlet-110-released.html' title='Restlet 1.1.0 released'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7004556344182607085</id><published>2008-10-29T16:41:00.005+08:00</published><updated>2008-10-29T23:10:48.195+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RPC'/><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><title type='text'>GWT RPC from non-servlet-container (1)</title><content type='html'>GWT is indeed a beautiful toolkit which does perfect jobs on client side. The most sparking point which I like most is that it is ALL ABOUT JAVA. So it inherits all those beautiful, highly efficient, well-thought-and-examined Java best practices, besides you have so many brilliant tools to use. And BANG!, it compiles cross-platform javascript codes which are run on most of popular browsers nicely. Since it is pure HTTP stuff, it can talks any kind of backend services via web using standard tech such as XML or JSON.&lt;br /&gt;&lt;br /&gt;One minor speck is on GWT's proprietary RPC function, in where the backend must be Java and running in a servlet container. There might be some efforts taken on somewhere to let GWT RPC talk with services done other than Java, for example this &lt;a href="http://code.google.com/p/python-gwt-rpc/"&gt;one&lt;/a&gt;. I would like to try something simpler, let GWT RPC being served by non-servlet-container.  Although servlet DO rule the market, but still there is alternative, such as &lt;a href="http://www.restlet.org/"&gt;Restlet&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The not so much a secret of GWT RPC&lt;/h3&gt;Thanks for GWT team's great job, the implementation of service-side GWT RPC is such a breeze which has good structure and not so difficult to get extracted out to be used outside servlet-container.&lt;br /&gt;&lt;br /&gt;Actually, the key part of a RPC call is consists of following statements:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;&lt;br /&gt;RPCRequest rpcRequest = RPC.decodeRequest(payload, this.getClass(), this);&lt;br /&gt;RPC.invokeAndEncodeResponse(this, rpcRequest.getMethod(),&lt;br /&gt;rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;For&lt;code&gt; RPC.decodeRequest&lt;/code&gt; method:&lt;ul&gt;&lt;li&gt;The first argument, the &lt;code&gt;payload&lt;/code&gt;,  is a UTF-8 string directly read from the input stream client request, no weird encode/decode in it;&lt;/li&gt;&lt;li&gt;The second argument is the class which implements  this RPC's &lt;code&gt;RemoteService&lt;/code&gt; interface. So it is the target class in the RPC method is defined;&lt;/li&gt;&lt;li&gt;The last argument should be an instance of &lt;code&gt;SerializationPolicyProvider&lt;/code&gt;. It provides an instance of &lt;code&gt;SerializationPolicy&lt;/code&gt; which instructs how to serialize a Java object from/to a string payload. This is one of the tricky parts which I will explain later.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;RPC.decodeRequest&lt;/code&gt; method returns an instance of RPCRequest which takes all necessary data for the RPC call.&lt;br /&gt;&lt;br /&gt;The second statement is easier to understand, in which the first argument is the target instance on which this RPC call is to be invoked. The &lt;code&gt;RPC.invokeAndEncodeResponse&lt;/code&gt; methods also return a UTF-8 string as result in JSON format (either success or failure). This string can be written back directly to GWT client (the current implementation is to gzip it first).&lt;br /&gt;&lt;br /&gt;According to aforementioned, seems we can serve a GWT RPC call from an non-servlet container by:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Prepare an instance of &lt;code&gt;SerializationPolicyProvider&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Get to know where to load your class and how to create an instance from it;&lt;/li&gt;&lt;li&gt;Read a UTF-8 string from HTTP request;&lt;/li&gt;&lt;li&gt;Create an instance of &lt;code&gt;RPCRequest&lt;/code&gt; and call &lt;code&gt;RPC.invokeAndEncodeResponse&lt;/code&gt; as illustrated above. &lt;/li&gt;&lt;li&gt;Write the UTF-8 string back to HTTP response, which content-type must be &lt;code&gt;application/json;charset=utf-8&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Where &lt;code&gt;SerializationPolicy&lt;/code&gt; come from&lt;/h3&gt;&lt;br /&gt;&lt;code&gt;SerializationPolicy&lt;/code&gt; is something new after 1.4.&lt;br /&gt;&lt;a href="file:///D:/devtools/java/google/gwt-windows-1.5.3/doc/html/com.google.gwt.doc.DeveloperGuide.RemoteProcedureCalls.html"&gt;&lt;/a&gt;&lt;blockquote&gt;&lt;a href="http://code.google.com/webtoolkit/documentation/com.google.gwt.doc.DeveloperGuide.RemoteProcedureCalls.html"&gt;RPC&lt;/a&gt; now generates a serialization         policy file during compilation.  The serialization policy file contains a whitelist of allowed types which may be         serialized.  Its name is a strong hash name followed by &lt;code&gt;.gwt.rpc&lt;/code&gt;.  This file must be deployed to your web         server as a public resource, accessible from a          &lt;a href="http://code.google.com/webtoolkit/documentation/com.google.gwt.user.server.rpc.RemoteServiceServlet.html"&gt;RemoteServiceServlet&lt;/a&gt;         via &lt;code&gt;ServletContext.getResource()&lt;/code&gt;.  If         it is not deployed properly, RPC will run in 1.3.3 compatibility mode and refuse to serialize types implementing         &lt;a href="http://code.google.com/webtoolkit/documentation/java.io.Serializable.html"&gt;Serializable&lt;/a&gt;. (&lt;a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=1297"&gt;#1297&lt;/a&gt;)&lt;/blockquote&gt;&lt;br /&gt;Basically, for each &lt;code&gt;RemoteServiceServlet&lt;/code&gt; implementation, there is one policy file generated which has a strong hash name. This name is passed by the RPC request payload. We can then use it together with the utility method &lt;code&gt;SerializationPolicyLoader.getSerializationPolicyFileName&lt;/code&gt; to load a &lt;code&gt;SerializationPolicy&lt;/code&gt; instance. The question is where to find that file under our non-servlet-container environment (says Restlet) and how smart it could be.&lt;br /&gt;&lt;br /&gt;The next installment I am going to talk about how to create a GWT application backending with Restlet. Hope it will be fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7004556344182607085?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7004556344182607085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7004556344182607085' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7004556344182607085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7004556344182607085'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/gwt-rpc-from-non-servlet-container-1.html' title='GWT RPC from non-servlet-container (1)'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-1948564335583563740</id><published>2008-10-22T23:22:00.003+08:00</published><updated>2008-10-22T23:41:07.805+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scan package</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;很多时候，需要动态的检查某个package下是否包含特定的类，比如继承了某个接口，或是附加上了某个annotation。&lt;br /&gt;&lt;br /&gt;这是个典型的听上去容易，做起来麻烦的任务。&lt;br /&gt;&lt;br /&gt;如果package的classpath属于&lt;code&gt;file://&lt;/code&gt;一类，可以直接使用&lt;code&gt;Class.getResourceAsStream("your/package")&lt;/code&gt;打开一个text stream, 其中的每一行为package包含的每一个元素。&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import scala.io.{Source}&lt;br /&gt;&lt;br /&gt;for(&lt;br /&gt;line &amp;lt;- Source.fromInputStream(aClass.getResourceAsStream("your/package")).getLines&lt;br /&gt;name = line.trim&lt;br /&gt;if match(name)&lt;br /&gt;}yield{&lt;br /&gt;Class.forName(name)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;但是如果package位于某一个jar文件中则需要遍历jar file中对应的每一个jar entry。&lt;br /&gt;&lt;br /&gt;庆幸的是，始终可以在open source社区中找到"先人"的贡献。&lt;br /&gt;&lt;br /&gt;如果你使用Spring (v 2+)，一定会对Spring中新增的annotation wire印象深刻，其中包括一个自动在某个package下寻找符合条件的bean的功能。&lt;br /&gt;&lt;br /&gt;这个package scanning的功能由&lt;code&gt;org.springframework.context.annotation.ClassPathBeanDefinitionScanner&lt;/code&gt;这个类来完成。默认的设定是找出指定package下带有&lt;code&gt;@Component&lt;/code&gt;的类。不过由于Spring良好的结构，很容易进行扩展。&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;val reg = new SimpleBeanDefinitionRegistry&lt;br /&gt;val scanner = new ClassPathBeanDefinitionScanner(reg, false)&lt;br /&gt;scanner.setIncludeAnnotationConfig(false)&lt;br /&gt;scanner.addIncludeFilter(new AssignableTypeFilter(classOf[Object]))&lt;br /&gt;scanner.scan("your.pkg")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Scanner依赖一个&lt;code&gt;TypeFilter&lt;/code&gt;来选择感兴趣的类。在上面的代码中禁止了预先设置的filter，并且用一个&lt;code&gt;AssignableTypeFilter&lt;/code&gt;来代替，因此选择所有的类。&lt;br /&gt;一旦scan结束，找到的类定义(&lt;code&gt;BeanDefinition&lt;/code&gt;)会被放入&lt;code&gt;BeanDefinitionRegistry&lt;/code&gt;这样一个结构中。上面的代码中，使用了&lt;code&gt;SimpleBeanDefinitionRegistry&lt;/code&gt;这样一个简单的实现。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-1948564335583563740?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/1948564335583563740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=1948564335583563740' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1948564335583563740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/1948564335583563740'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/scan-package.html' title='Scan package'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7341701502605365121</id><published>2008-10-09T22:31:00.003+08:00</published><updated>2008-10-09T23:21:52.030+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala implcit parameters on constructor</title><content type='html'>Scala's implicit conversion is a so much cool feature which allows you &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=179766"&gt;extends&lt;/a&gt; &lt;a href="http://scalada.blogspot.com/2008/03/implicit-conversions-magical-and.html"&gt;exiting &lt;/a&gt;&lt;a href="http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6"&gt;libraries&lt;/a&gt; without changing source codes. It works like a wrapper but transparent to users.&lt;br /&gt;&lt;br /&gt;Says I have a string representing a URL, by implicit conversion&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;implicit def toMyRichString(url:String) = new MyRichString(str){&lt;br /&gt;   def getText={&lt;br /&gt;    //...&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to make a String richer (even richer than RichString). I can use&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;"http://www.scala-lang.org".getText&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to retrieve the html text from Scala site.&lt;br /&gt;&lt;br /&gt;The possibility is unlimited and the feature is almost free. It does have performance &lt;a href="http://villane.wordpress.com/2008/02/02/learning-scala-performance-impact-of-implicit-conversions/"&gt;lost&lt;/a&gt;, but comparing to other dynamic language (such as Groovy), this is way much better.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.scala-lang.org/node/114"&gt;Implicit parameter&lt;/a&gt; is even cooler but subtle. It kinds of allows you to provide a default value to your function parameter so you can invoke a function without specifying that parameter. The requirement is you must provide such a value (of same type) in the context of that invoking.&lt;br /&gt;&lt;br /&gt;Implicit parameter can also be used on constructor.  This gives me such an idea that this could be used in some scenario of &lt;a href="http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/"&gt;dependency injection&lt;/a&gt; or auto-wiring. The first case I think out is about log. So here is an example:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;class Log(val name:String){&lt;br /&gt; def log(msg:String){&lt;br /&gt;   println("["+name+"] " + msg)&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;implicit def anyRefToLogger(t:AnyRef) = new Log(t.getClass.getName)&lt;br /&gt;&lt;br /&gt;class Test(val arg:String)(implicit log: AnyRef=&gt;Log){&lt;br /&gt; log.log("Hello " + arg)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;new Test("Implicit Cool")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which may seems trivial but quite interesting to me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7341701502605365121?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7341701502605365121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7341701502605365121' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7341701502605365121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7341701502605365121'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/scala-implcit-parameters-on-constructor.html' title='Scala implcit parameters on constructor'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-3385221740900266743</id><published>2008-10-04T23:15:00.003+08:00</published><updated>2008-10-04T23:21:43.458+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Lazy Fibonacci stream in Scala</title><content type='html'>I tried to create a lazy infinite Fibonacci stream using Scala, here are my two solutions.&lt;br /&gt;&lt;br /&gt;The first one is a naive one using inner function:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def fib:Stream[Long]={&lt;br /&gt;  def fibInner(f0:Long, f1:Long):Stream[Long]={&lt;br /&gt;    Stream.cons(f0, fibInner(f1, f0+f1))&lt;br /&gt;  }&lt;br /&gt;  fibInner(1,2)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The second one is ported from Haskell:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def fib2:Stream[Long]={&lt;br /&gt;  Stream.cons(1, Stream.cons(2, fib2.zip(fib2.tail).map(x=&gt;x._1+x._2)))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Although both of them works but the second one is way slower than the first one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-3385221740900266743?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/3385221740900266743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=3385221740900266743' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3385221740900266743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3385221740900266743'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/10/lazy-fibonacci-stream-in-scala.html' title='Lazy Fibonacci stream in Scala'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-6313529154253872070</id><published>2008-09-27T21:15:00.001+08:00</published><updated>2008-09-27T21:26:47.932+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala syntax primer</title><content type='html'>Good Scala syntax reference on &lt;a href="http://jim-mcbeath.blogspot.com/2008/09/scala-syntax-primer.html"&gt;jim-mcbeath.&lt;/a&gt; Another worthy-reading is by &lt;a href="http://blogs.sun.com/sundararajan/entry/scala_for_java_programmers"&gt;A. Sundararajan&lt;/a&gt; and &lt;a href="http://blogs.sun.com/sundararajan/entry/scala_for_java_programmers_part"&gt;part 2.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-6313529154253872070?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/6313529154253872070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=6313529154253872070' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6313529154253872070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6313529154253872070'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/scala-syntax-primer.html' title='Scala syntax primer'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-9002294995454308340</id><published>2008-09-27T21:07:00.002+08:00</published><updated>2008-09-27T21:13:59.112+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Apple开始在香港销售不加锁的iPhone 3G</title><content type='html'>&lt;a href="http://news.yahoo.com/s/ap/20080927/ap_on_bi_ge/as_hong_kong_iphone"&gt;看到Yahoo新闻&lt;/a&gt;，说Apple已经开始在香港销售不加锁的iPhone 3G手机。8G的大约5400港币，16G的大约6200港币。&lt;br /&gt;&lt;blockquote&gt;The move seems to depart from its previous strategy of introducing the popular device capable of 3G, or third-generation, through &lt;span class="yshortcuts" id="lw_1222514129_4"&gt;specific service providers&lt;/span&gt; in 22 nations.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;这似乎预示着前些日子的传闻 - iPhone 3G进入内地有些矛盾。是否与内地的运营商谈判又出现了分歧，才走这样一步"曲线救国"的棋？毕竟，进入香港等于就是进入了内地，6000多人民币对于去香港的内地人而言，也不算是非常的奢侈品。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-9002294995454308340?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/9002294995454308340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=9002294995454308340' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/9002294995454308340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/9002294995454308340'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/appleiphone-3g.html' title='Apple开始在香港销售不加锁的iPhone 3G'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-6135577511472831001</id><published>2008-09-26T22:45:00.004+08:00</published><updated>2008-09-26T23:48:02.157+08:00</updated><title type='text'>恢复被禁用的Windows服务</title><content type='html'>刚才在等待诺顿更新的时候，闲的无事，便打开管理工具中的服务选项瞅瞅。一眼看到那个“臭名昭著”的RPC服务处在自动开启的状态，便想起来前几年中冲击波病毒的惨状，便随手把RPC服务停止并且禁用了。&lt;br /&gt;&lt;br /&gt;过了一会儿，因为需要便重启了系统，谁知恐慌便到来了。&lt;br /&gt;&lt;br /&gt;首先是系统变得异常缓慢。然后是登陆后发现一些应用没有启动，网络连接消失了。发现状况不对之后，立刻感到服务选项去。发现RPC服务和其他相关的服务没有启动，并且无法启动。而且通过右键菜单选择属性选项无效，无法更改RPC服务的启动状态。无法使用sc命令修改状态，甚至在安全模式中也不起作用。&lt;br /&gt;&lt;br /&gt;家里有没有第二台电脑，一阵眩晕与慌乱。&lt;br /&gt;&lt;br /&gt;突然发现可以用iPhone，于是找到&lt;a href="http://www.poptool.net/server/p315/J31538695.shtml"&gt;这篇文章&lt;/a&gt;。总结如下：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;如果无法使用sc命令修改状态的话，可以使用regedit直接编辑服务的状态设定，路径为&lt;span style="font-family: courier new;"&gt;hkey_local_machine\system\currentcontrol-set\services\rpcss&lt;/span&gt;，你也可以在services路径下找到其他的服务；&lt;/li&gt;&lt;li&gt;将"start"的值由4该为2，即由disable改为auto；&lt;/li&gt;&lt;li&gt;很重要的一步，需要将&lt;span style="font-family: courier new;"&gt;hkey_local_machine\system\curr-entcontrolset\hardwareprofiles\0001\system\currentcontrolset\enum\root\legacy_rpcss&lt;/span&gt;删除。&lt;/li&gt;&lt;/ol&gt;然后重新启动系统即可。&lt;br /&gt;&lt;br /&gt;这个故事告诉我们如下教训：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;做事不要冲动&lt;/li&gt;&lt;li&gt;要相信专家，诺顿在系统服务漏洞检查时并没有抱怨RPC服务的事宜；&lt;/li&gt;&lt;li&gt;半吊子最要不得&lt;/li&gt;&lt;li&gt;苹果比Windows似乎更畏难中见人心&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-6135577511472831001?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/6135577511472831001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=6135577511472831001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6135577511472831001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6135577511472831001'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/windows.html' title='恢复被禁用的Windows服务'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7089870215899116944</id><published>2008-09-21T12:56:00.013+08:00</published><updated>2009-02-15T11:31:05.094+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DSL'/><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Scala smooths ORM and more</title><content type='html'>Two Scala features', object as module and implicit convert, can greatly ease your daily hibernate coding.&lt;br /&gt;&lt;br /&gt;I do love the &lt;a href="http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html"&gt;ORM module&lt;/a&gt; (&lt;a href="http://grails.org/GORM"&gt;GORM&lt;/a&gt;) provided &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt;, which allow you to be focus on plain &lt;a href="http://www.grails.org/GORM+-+Creating+a+domain+class"&gt;domain classes&lt;/a&gt; and these domain classes get enhanced later on by the container(Grails). So your plain domain classes (or POGOs) automatically have functionality of presist, such as &lt;a href="http://www.grails.org/GORM+-+CRUD"&gt;save, delete, and queries&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Grails implements this by a lot of complicated &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; MOP tricks(&lt;a href="http://groovy.codehaus.org/Dynamic+Groovy"&gt;1&lt;/a&gt;,&lt;a href="http://groovy.codehaus.org/ExpandoMetaClass"&gt;2&lt;/a&gt;). Basically, once such a protocol is defined, it is carried by domain classes along whole life cycle. Even your domain object is not currently working under persist layer, it still has save and delete method. This might not be a big deal in most cases. However, dynamic methods cost great much, it rings the bell about performance issue.&lt;br /&gt;&lt;br /&gt;Implementing such feature in current Java programming work is also not good. Usually, such kind of framework-supported-enhancement involves lots of bytecode enhancement or instance proxying related reflection. Framework like &lt;a href="https://activeobjects.dev.java.net/"&gt;ActiveObjects &lt;/a&gt;enhances your domain classes using the latter approach(correct me if I am wrong). As a result, you are not be able to create your domain instance using &lt;code&gt;new&lt;/code&gt; keyword (your domain classes are enhanced hence changed). You have to create domain instance using a factory method provided by framework. It is faster, but break your POJOs in this or that ways. Your thin domain class will have this or that new injected methods or properties which might break even serialization.&lt;br /&gt;&lt;br /&gt;So, how Scala implicit conversion do about this? My answer is implicit conversion and object as modules. Say I have a domain class Book which is implemented as following Scala code (you can do this in Java also).&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import org.edgebox.orm.Entity&lt;br /&gt;import scala.reflect.{BeanProperty=&gt;BP}&lt;br /&gt;class Book extends Entity{&lt;br /&gt;@BP&lt;br /&gt;var id=0L&lt;br /&gt;@BP&lt;br /&gt;var name:String = null&lt;br /&gt;@BP&lt;br /&gt;var price = 0&lt;br /&gt;// other properties are omitted for simplicity&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Later on when you use this domain class in your persist layer, you can simply do following:&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;import org.edgebox.orm.ORM&lt;br /&gt;import org.edgebox.orm.Query._&lt;br /&gt;&lt;br /&gt;class APersistService(val orm:ORM){&lt;br /&gt;import orm._&lt;br /&gt;def aPersistMethod = {&lt;br /&gt;  val Book = classOf[Book]&lt;br /&gt;  // doing query&lt;br /&gt;  Book.all.filter(ilike("name", "scala")).order(asc("price")).fetch&lt;br /&gt;  // doing get by id&lt;br /&gt;  val book = Book.get(1)&lt;br /&gt;  // update book ...&lt;br /&gt;  book.save&lt;br /&gt;  //...&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-size:85%;"&gt;The query syntax is stolen from Google AppEngine (or Django).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Quite simple, the trick is the import orm._ clause. You can treat instance orm as a module, the import clause introduces all elements of that orm instance into this PersistService. The orm instances has two interesting implicit convert functions:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;type EntityType = T forSome{ type T &lt;: Entity}   &lt;br /&gt;implicit def entityWrapper(e:EntityType) = new RichEntity   &lt;br /&gt;implicit def entityTypeWrapper(et:Class[_&lt;:Entity])= new RichEntityType &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So, when you tries to call book.save although your domain class knows nothing about persistence, the persist module (&lt;code&gt;orm&lt;/code&gt; instance) and implicit conversion can nicely handle this for you, automatically and transparently by Scala compiler.&lt;br /&gt;&lt;br /&gt;Benefits?&lt;br /&gt;&lt;ol&gt;&lt;li&gt;You keep your domain class clean, no one is gonna inject anything into your domain class or intercept any calls during your operations;&lt;/li&gt;&lt;li&gt;Very minor performance overhead, you gotta no performance lose when you are working with your domain class and very minor performance overhead when you are trying to using specific layer-related method;&lt;/li&gt;&lt;li&gt;Object as module also bring flexibility; instance of &lt;code&gt;orm&lt;/code&gt; can be configured using various possibility and also Spring-enabled;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The most interesting point is (which is also my most favorite part), this approach introduces a more clean and flexible design onto multi-layered system. You can focus your domain class but when working on different layer you just need to import different  function modules which automatically enhance your domain classes with layer-specific function. For example, our domain class might be able to do serialization by calling &lt;code&gt;book.toJson&lt;/code&gt; or &lt;code&gt;book.toRdf&lt;/code&gt; under layer handling Restful representation. And using which kind of serialization is totally relied on a simple import clause.&lt;/li&gt;&lt;/ol&gt;You can find above sample code under http://svn.assembla.com/svn/edgebox/edgebox/branch/edgebox/, under package &lt;code&gt;org.edgebox.orm&lt;/code&gt;. At current moment, this toolkit is tightly based on Spring and Hibernate (as Grails does).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Updates&lt;/h3&gt;&lt;br /&gt;The code of RichEntityType and RichEntity are:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;  class RichEntityType[T](val self:Class[T], val dao:Dao[T]) extends Proxy{&lt;br /&gt;    def get(id:Serializable)={&lt;br /&gt;      dao.get(id)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  class RichEntity[T&lt;:Entity](val self:T, val dao:Dao[T]) extends Proxy{&lt;br /&gt;    def save()={&lt;br /&gt;      dao.save(self)&lt;br /&gt;      self&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7089870215899116944?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7089870215899116944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7089870215899116944' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7089870215899116944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7089870215899116944'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/scala-smooths-orm-and-more.html' title='Scala smooths ORM and more'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-4994034868336713209</id><published>2008-09-21T12:35:00.001+08:00</published><updated>2008-09-21T12:37:01.919+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><category scheme='http://www.blogger.com/atom/ns#' term='reading'/><title type='text'>买书3本</title><content type='html'>&lt;ul&gt;&lt;li&gt;我为什么要写作&lt;/li&gt;&lt;li&gt;梦十夜&lt;/li&gt;&lt;li&gt;权利与荣耀&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-4994034868336713209?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/4994034868336713209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=4994034868336713209' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4994034868336713209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4994034868336713209'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/3.html' title='买书3本'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-723834549704068034</id><published>2008-09-19T22:30:00.001+08:00</published><updated>2008-09-19T22:32:31.023+08:00</updated><title type='text'>Cisco buys Jabber</title><content type='html'>Just &lt;a href="http://news.yahoo.com/s/nm/20080919/wr_nm/jabber_cisco_dc"&gt;news&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Cisco Systems Inc said on Friday it plans to buy privately held Jabber Inc, which specializes in instant messaging software, to bolster its own line of Internet-based communications products.&lt;/blockquote&gt;非常令人吃惊，当然近些年来Cisco在所谓的Web 2.0上投入巨大。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-723834549704068034?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/723834549704068034/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=723834549704068034' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/723834549704068034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/723834549704068034'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/cisco-buys-jabber.html' title='Cisco buys Jabber'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7402116632099268417</id><published>2008-09-19T13:37:00.003+08:00</published><updated>2008-09-19T14:04:18.968+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Array and repeated parameters</title><content type='html'>I met an interesting &lt;a href="http://www.scala-lang.org/"&gt;Scala &lt;/a&gt;problem these days, which is about repeated parameter of a function. In Java you can specify varargs on a method,&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public void a(String... args){&lt;br /&gt; ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Inside that function, you get &lt;code&gt;args&lt;/code&gt; as an Array of String.&lt;br /&gt;&lt;br /&gt;In Scala, we have similar feature but called &lt;span style="font-style: italic;"&gt;repeated parameter&lt;/span&gt;.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def a(args:String*)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.artima.com/shop/programming_in_scala"&gt;Scalabook &lt;/a&gt;(section 8.8) says you get that args as an instance of Array[String]. But &lt;a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf"&gt;Scala reference(pdf)&lt;/a&gt; has different explanation.&lt;br /&gt;&lt;blockquote&gt;The type of such a repeated parameter inside the method is then&lt;br /&gt;the sequence type scala.Seq[T ]. &lt;/blockquote&gt;&lt;br /&gt;The Scala reference is right. Actually, the implementation gives you an instance of &lt;a href="http://scala-tools.org/scaladocs/scala-library/2.7.1/scala/runtime/BoxedObjectArray.html"&gt;scala.runtime.BoxedObjectArray&lt;/a&gt;. You can treat it as an instance of Array[String] but you can not pass it as an instance of Array[String].&lt;br /&gt;&lt;br /&gt;Say we have another method&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;def b(is:Array[String])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you want to pass args instance you get in method &lt;code&gt;a&lt;/code&gt; to method &lt;code&gt;b&lt;/code&gt;, you get compile error:&lt;br /&gt;&lt;blockquote&gt;error: type mismatch&lt;br /&gt;found: String*&lt;br /&gt;required: Array[String]&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;So here is my solution to this.&lt;br /&gt;&lt;br /&gt;If you want to use &lt;code&gt;args&lt;/code&gt; as an Array[String] with method a or pass it to Java, you need to unboxed it first.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;args.asInstanceOf[BoxedObjectArray].unbox(classOf[String]).&lt;br /&gt;    asInstanceOf[Array[String]]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you want to pass &lt;code&gt;args&lt;/code&gt; to another method, like b mentioned before, in Scala as paramter of type Array[String], you only need to get an array from that Seq&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;args.toArray[String]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Although you get another instance of &lt;code&gt;BoxedAnyObject&lt;/code&gt;, but when passing parameter to method b, scala compiler can auto-unbox for you.&lt;br /&gt;&lt;br /&gt;For interesting implementation detail, see David's excellent writing about &lt;a href="http://www.drmaciver.com/2008/06/scala-arrays/"&gt;Scala array&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7402116632099268417?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7402116632099268417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7402116632099268417' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7402116632099268417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7402116632099268417'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/scala-array-and-repeated-parameters.html' title='Scala Array and repeated parameters'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-776610568270800541</id><published>2008-09-17T14:55:00.002+08:00</published><updated>2008-09-17T14:58:50.745+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='rsh'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><title type='text'>News about RSH 0.8</title><content type='html'>&lt;a href="http://www.pathf.com/blogs/2008/09/a-mea-culpa-and-a-launch-date-for-really-simple-history-08/"&gt;Agile Ajax&lt;/a&gt; talked about news and changes in upcoming &lt;a href="http://code.google.com/p/reallysimplehistory/" title="Really Simple History"&gt;RSH&lt;/a&gt; 0.8, which mentioned following enhancement will be added in v 0.8:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a smaller footprint&lt;/li&gt;&lt;li&gt;a new API&lt;/li&gt;&lt;li&gt;easier configurability&lt;/li&gt;&lt;li&gt;less complexity for mainstream use cases&lt;/li&gt;&lt;li&gt;explicit support for IE8, Safari 3, Firefox 3, Flock and Chrome&lt;/li&gt;&lt;li&gt;more modularity and pluggability thanks to functional programming patterns espoused by Douglas Crockford&lt;/li&gt;&lt;li&gt;easier integration with popular Ajax toolkits&lt;/li&gt;&lt;li&gt;bug fixes&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-776610568270800541?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/776610568270800541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=776610568270800541' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/776610568270800541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/776610568270800541'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/news-about-rsh-08.html' title='News about RSH 0.8'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-6236904347759281635</id><published>2008-09-16T14:56:00.003+08:00</published><updated>2008-09-16T16:37:43.906+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala, Object as Module</title><content type='html'>Package provides no way to abstract?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Package is not configurable&lt;/li&gt;&lt;li&gt;Package is not inheritable&lt;/li&gt;&lt;/ul&gt;Self type: (scalabook) self type is the assumed type for this.&lt;br /&gt;&lt;blockquote&gt;If a formal parameter is given, it can be used as an alias for the reference this throughout the body of the template. If the formal parameter comes with a type T , this deﬁnition affects the self type S of the underlying class or object as follows: Let C be the type of the class or trait or object deﬁning the template. If a type T is given for the formal self parameter, S is the greatest lower bound of T and C. If no type T is given, S is just C. Inside the template, the type of this is assumed to be S.&lt;/blockquote&gt;举个简单的例子， 对于一个trait A而言，无法预期会被哪一个class或是object继承(mixin)，因此在这个trait中，this默认为类型A，在这个trait中只能访问这个trait或是这个trait的父类型的元素。然而&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;trait A{&lt;br /&gt; self: B=&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;引入了如下变化:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;只有类型B或B的子类型class或object可以继承A(mixin)，否则编译错误；&lt;br /&gt;&lt;/li&gt;&lt;li&gt;trait A内部还可以使用类型B所定义的元素；&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-6236904347759281635?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/6236904347759281635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=6236904347759281635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6236904347759281635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/6236904347759281635'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/scala-object-as-module.html' title='Scala, Object as Module'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-3083831563838409080</id><published>2008-09-15T13:15:00.002+08:00</published><updated>2008-09-15T13:18:12.124+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>买书4本</title><content type='html'>&lt;ol&gt;&lt;li&gt;一千零一夜&lt;br /&gt;&lt;/li&gt;&lt;li&gt;摩诃婆罗多&lt;/li&gt;&lt;li&gt;居鲁士的教育&lt;/li&gt;&lt;li&gt;呓语梦中人 (Dream Angus)&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-3083831563838409080?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/3083831563838409080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=3083831563838409080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3083831563838409080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3083831563838409080'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/4.html' title='买书4本'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-3213685212992441084</id><published>2008-09-14T22:20:00.002+08:00</published><updated>2008-09-14T22:25:04.027+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pdfbox'/><title type='text'>Pdfbox now in Apache incubation</title><content type='html'>I just realized that PDFBox now is an Apache incubation project. I got this news from PDFBox's bug tracker on sourceforge.&lt;br /&gt;&lt;br /&gt;So now new PDFBox project site is at http://incubator.apache.org/pdfbox/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-3213685212992441084?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/3213685212992441084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=3213685212992441084' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3213685212992441084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3213685212992441084'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/pdfbox-now-in-apache-incubation.html' title='Pdfbox now in Apache incubation'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-5700243120241050823</id><published>2008-09-14T16:36:00.001+08:00</published><updated>2008-09-14T16:37:41.706+08:00</updated><title type='text'>Test syntaxhighlighter</title><content type='html'>&lt;pre name="code" class="java"&gt;&lt;br /&gt;class Helo{}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-5700243120241050823?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/5700243120241050823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=5700243120241050823' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5700243120241050823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/5700243120241050823'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/test-syntaxhighlighter.html' title='Test syntaxhighlighter'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-8792805496233488389</id><published>2008-09-14T15:35:00.002+08:00</published><updated>2008-09-14T16:29:08.671+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tika'/><category scheme='http://www.blogger.com/atom/ns#' term='lucene'/><title type='text'>Parsing and extracting using Tika</title><content type='html'>在最早的那本Lucene in Action书中提到，如果用户需要对非文本内容进行索引的话需要首先将文本内容从二进制格式的文档中抽取出来。 因此针对不同类型的文件格式，需要不同处理。当然open community中已经有了许多成熟的方案来对付，PDF, MS-Word, HTML等。不过逐一使用这些不同的工具，为不同的文件格式进行开发，也是相当头疼的事情。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://incubator.apache.org/tika/"&gt;Apache Tika&lt;/a&gt;的出现，为我这样的懒人带来了无穷的便利。&lt;br /&gt;&lt;br /&gt;首先，Tika是一个内容抽取的工具集合(a toolkit for text extracting)。它集成了POI, &lt;a href="http://www.pdfbox.org/"&gt;Pdfbox&lt;/a&gt; 并且为文本抽取工作提供了一个统一的界面。其次，Tika也提供了便利的扩展API，用来丰富其对第三方文件格式的支持。&lt;br /&gt;&lt;br /&gt;在当前的0.2-SNAPSHOT版本中， Tika提供了对如下文件格式的支持:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;PDF - 通过&lt;a href="http://www.pdfbox.org/"&gt;Pdfbox&lt;/a&gt;&lt;/li&gt;&lt;li&gt;MS-* - 通过&lt;a href="http://poi.apache.org/"&gt;POI&lt;/a&gt;&lt;/li&gt;&lt;li&gt;HTML - 使用&lt;a href="http://sourceforge.net/projects/nekohtml"&gt;nekohtml&lt;/a&gt;将不规范的html整理成为xhtml&lt;/li&gt;&lt;li&gt;OpenOffice 格式 - Tika提供&lt;/li&gt;&lt;li&gt;Archive - zip, tar, gzip, bzip等&lt;/li&gt;&lt;li&gt;RTF - Tika提供&lt;/li&gt;&lt;li&gt;Java class - Class解析由&lt;a href="http://asm.objectweb.org/"&gt;ASM&lt;/a&gt;完成&lt;/li&gt;&lt;li&gt;Image - 只支持图像的元数据抽取&lt;/li&gt;&lt;li&gt;XML&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Tika的API十分便捷，核心是Parser interface，其中定义了一个parse方法：&lt;br /&gt;&lt;code&gt;public void parse(InputStream stream, ContentHandler handler, Metadata metadata)&lt;/code&gt;&lt;br /&gt;用stream参数传递需要解析的文件流， 文本内容会被传入handler，而元数据会更新至metadata。&lt;br /&gt;&lt;br /&gt;可以使用Tika的ParserUtils工具来根据文件的&lt;code&gt;mime-type&lt;/code&gt;来得到一个适当的Parser来进行解析工作。或者Tika还提供了一个AutoDetectParser根据不同的二进制文件的特殊格式 (比如说Magic Code)，来寻找适合的Parser。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-8792805496233488389?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/8792805496233488389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=8792805496233488389' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8792805496233488389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8792805496233488389'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/parsing-and-extracting-using-tika.html' title='Parsing and extracting using Tika'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-4692870791018188276</id><published>2008-09-13T14:47:00.001+08:00</published><updated>2008-09-13T14:49:39.304+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='photo'/><title type='text'>Small Elephant</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;img src="http://rephoto.jpn.org/img/photo/2LGSakCCNds5q6acKUkrBKKs_500.jpg" /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;(via &lt;a href="http://rephoto.jpn.org/rephoto/view/742686"&gt;rePhoto&lt;/a&gt;)&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-4692870791018188276?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/4692870791018188276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=4692870791018188276' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4692870791018188276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/4692870791018188276'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/small-elephant.html' title='Small Elephant'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-3138324794947948826</id><published>2008-09-13T13:53:00.003+08:00</published><updated>2008-09-13T14:14:29.880+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='file-icons'/><category scheme='http://www.blogger.com/atom/ns#' term='web-resources'/><title type='text'>Free file icons</title><content type='html'>因为需要，寻找了一下不同类型图标的PNG文件，Google给我了这个&lt;a href="http://www.splitbrain.org/projects/file_icons"&gt;页面&lt;br /&gt;&lt;/a&gt;。包括了60多种各种常见文件类型的PNG图标, 棒极了，示例如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_KwZCZ51s6OE/SMtZvFGL1lI/AAAAAAAAAEU/dgs0ubU2KrI/s1600-h/fileicons.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_KwZCZ51s6OE/SMtZvFGL1lI/AAAAAAAAAEU/dgs0ubU2KrI/s320/fileicons.PNG" alt="" id="BLOGGER_PHOTO_ID_5245384856359917138" border="0" /&gt;&lt;/a&gt;而且文件的使用十分友好：&lt;br /&gt;&lt;blockquote&gt;All &lt;span class="search_hit"&gt;icon&lt;/span&gt;s are given away to the Public Domain. You can use them in any way you like, with no restrictions. &lt;/blockquote&gt;真是太感谢了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-3138324794947948826?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/3138324794947948826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=3138324794947948826' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3138324794947948826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/3138324794947948826'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2008/09/file-icons.html' title='Free file icons'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_KwZCZ51s6OE/SMtZvFGL1lI/AAAAAAAAAEU/dgs0ubU2KrI/s72-c/fileicons.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7375925352060323096</id><published>2007-11-14T10:52:00.001+08:00</published><updated>2007-11-14T10:52:47.680+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='pypy'/><title type='text'>PyPy</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;a href='http://codespeak.net/pypy/dist/pypy/doc/news.html'&gt;PyPy&lt;/a&gt;是一个Python语言开发的Python实现。因此，Python程序员可以直接使用Python语言本身，而不是C来改变底层Python实现的行为。（听上去像是一段绕口令)。&lt;br/&gt;&lt;br/&gt;Quote from Pypy:&lt;br/&gt;&lt;blockquote&gt;The PyPy project aims at producing a flexible and fast Python&lt;br/&gt;implementation.  The guiding idea is to translate a Python-level&lt;br/&gt;description of the Python language itself to lower level languages.&lt;br/&gt;Rumors have it that the secret goal is being faster-than-C which is&lt;br/&gt;nonsense, isn't it?&lt;/blockquote&gt;&lt;br/&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7375925352060323096?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7375925352060323096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7375925352060323096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7375925352060323096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7375925352060323096'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2007/11/pypy_14.html' title='PyPy'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-8197612486393756485</id><published>2007-11-12T11:41:00.003+08:00</published><updated>2008-09-13T13:44:46.044+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bnd'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven-Bundle-Plugin</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;除了使用&lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt;的&lt;acronym title="Plugin Development Environment"&gt;PDE&lt;/acronym&gt;之外，还可以使用&lt;a href="http://felix.apache.org/"&gt;Apache Felix&lt;/a&gt;项目提供的&lt;a href="http://cwiki.apache.org/FELIX/bundle-plugin-for-maven-bnd.html"&gt;Maven-Bundle-Plugin&lt;/a&gt;开进行&lt;a href="http://osgi.org/"&gt;OSGi&lt;/a&gt;的开发。&lt;br /&gt;Maven-Bundle-Plugin是建立在广受欢迎&lt;a href="http://www.aqute.biz/Code/Bnd"&gt;BND&lt;/a&gt;工具之上。换言之， MBP是Maven对于BND的一个封装，使得BND可以在Maven的标准过程中执行。因此BND定义的所有语法，都可以使用在MBP中。只不过，原先那些定义POM.xml文件中的那些元信息，需要在Maven的POM.xml中声明， 例子如下:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;build&amp;gt;&lt;br /&gt;&amp;lt;plugins&amp;gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt; &amp;lt;groupId&amp;gt;org.apache.felix&amp;lt;/groupId&amp;gt;&lt;br /&gt; &amp;lt;artifactId&amp;gt;maven-bundle-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt; &amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;&lt;br /&gt; &amp;lt;extensions&amp;gt;true&amp;lt;/extensions&amp;gt;&lt;br /&gt; &amp;lt;configuration&amp;gt;&lt;br /&gt;   &amp;lt;instructions&amp;gt;&lt;br /&gt;     &amp;lt;Export-Package&amp;gt;*&amp;lt;/Export-Package&amp;gt;&lt;br /&gt;     &amp;lt;Bundle-SymbolicName&amp;gt;org.lpny.desktop.log4j&amp;lt;/Bundle-SymbolicName&amp;gt;&lt;br /&gt;     &amp;lt;Import-Package&amp;gt;!*&amp;lt;/Import-Package&amp;gt;&lt;br /&gt;   &amp;lt;/instructions&amp;gt;&lt;br /&gt; &amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&amp;lt;/plugins&amp;gt;&lt;br /&gt;&amp;lt;/build&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;以上是一个用来把log4j (v.1.2.14)封装成为一个OSGi Bundle的定义。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="poweredbyperformancing"&gt;Powered by &lt;a href="http://scribefire.com/"&gt;ScribeFire&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-8197612486393756485?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/8197612486393756485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=8197612486393756485' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8197612486393756485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/8197612486393756485'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2007/11/maven-bundle-plugin.html' title='Maven-Bundle-Plugin'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-869230364755086797.post-7952326957058783090</id><published>2007-11-07T21:01:00.000+08:00</published><updated>2007-11-07T21:24:06.377+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>滑稽的本地化</title><content type='html'>刚刚在设置这个blog的时候看到这样一段奇怪的中文：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;blockquote&gt;您可以将其限制为仅对所选读者开放。&lt;br /&gt;但是，这些读者需要多做一个步骤才能阅读您的博客，那就是他们要先登录。&lt;/blockquote&gt;&lt;div style="text-align: left;"&gt;感觉像是一个外国人翻译的中文，读起来很是别扭。当然意思没有任何问题，只是总是感觉Google中国做的事情比较马虎，尤其是在本地化方面。       &lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/869230364755086797-7952326957058783090?l=betathings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://betathings.blogspot.com/feeds/7952326957058783090/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=869230364755086797&amp;postID=7952326957058783090' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7952326957058783090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/869230364755086797/posts/default/7952326957058783090'/><link rel='alternate' type='text/html' href='http://betathings.blogspot.com/2007/11/blog-post.html' title='滑稽的本地化'/><author><name>keke</name><uri>http://www.blogger.com/profile/00766149521444281749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
