<?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-9469017</id><updated>2011-12-14T19:55:51.886-08:00</updated><category term='ruby'/><category term='java'/><category term='generics'/><title type='text'>split-s</title><subtitle type='html'>martin's weblog</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>50</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9469017.post-8988415578326059643</id><published>2007-08-22T15:16:00.000-07:00</published><updated>2007-08-22T19:28:35.679-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='generics'/><title type='text'>Helping javac infer generic return types</title><content type='html'>One of my pet peeves with Java generics is that you can't pass the result of a method that returns a generic type whose bounds cannot be inferred from actual arguments directly to another method. This is particularly useful when passing an empty list obtained from Collections.emptyList() to a method:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class Test &lt;br /&gt; {&lt;br /&gt;&amp;nbsp;&amp;nbsp; static void foo(List&amp;lt;String&gt; list) {}&lt;br /&gt;  &lt;br /&gt;&amp;nbsp;&amp;nbsp;  public static void main(String[] args)&lt;br /&gt;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   foo(Collections.emptyList()); // doesn't compile&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt; }&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, that doesn't compile. It can be worked around by doing:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;List&amp;lt;String&gt; list = Collections.emptyList();&lt;br /&gt;    foo(list);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;It beats me why the compiler cannot infer the appropriate type for the list returned by Collections.emptyList() in the first example above. I understand why it would fail when 'foo' has multiple overloads, but it should work for the simple case when the method resolution is unambiguous.&lt;br /&gt;&lt;br /&gt;I recently &lt;a href="http://groups.google.com/group/google-guice/msg/2f4a4b7b30b067ba"&gt;came across&lt;/a&gt; an &lt;a href="http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12"&gt;obscure&lt;/a&gt; (yes, ugly and unintuitive) way of getting the first example to work. It consists in telling the compiler explicitly what to bind the return type to. This is the BNF definition, per the &lt;a href="http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html"&gt;JLS 3.0&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;MethodInvocation:&lt;br /&gt;&amp;nbsp;&amp;nbsp;        MethodName ( ArgumentList? )&lt;br /&gt;&amp;nbsp;&amp;nbsp;        Primary . &lt;b&gt;NonWildTypeArguments&lt;/b&gt;? Identifier ( ArgumentList? )&lt;br /&gt;&amp;nbsp;&amp;nbsp;        super . NonWildTypeArgumentsopt Identifier ( ArgumentList? )&lt;br /&gt;&amp;nbsp;&amp;nbsp;        ClassName . super . NonWildTypeArguments? Identifier ( ArgumentList? )&lt;br /&gt;&amp;nbsp;&amp;nbsp;        TypeName . NonWildTypeArguments Identifier ( ArgumentList? )&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And here's a concrete example:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;foo(Collections.&lt;b&gt;&amp;lt;String&gt;&lt;/b&gt;emptyList());&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/9469017-8988415578326059643?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/8988415578326059643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=8988415578326059643' title='49 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/8988415578326059643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/8988415578326059643'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2007/08/helping-javac-infer-generic-return.html' title='Helping javac infer generic return types'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>49</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-1886880365206963615</id><published>2007-02-25T16:05:00.000-08:00</published><updated>2007-02-25T16:12:18.385-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>rubydbc</title><content type='html'>&lt;a href="http://split-s.blogspot.com/2006/02/design-by-contract-for-ruby.html"&gt;Design by Contract for Ruby&lt;/a&gt; is now a &lt;a href="http://rubyforge.org/projects/rubydbc"&gt;Rubyforge project&lt;/a&gt;. Version 1.0.0 is available as a gem:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;gem install rubydbc&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-1886880365206963615?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/1886880365206963615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=1886880365206963615' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/1886880365206963615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/1886880365206963615'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2007/02/rubydbc.html' title='rubydbc'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-116330984787054688</id><published>2006-11-11T21:27:00.000-08:00</published><updated>2006-11-11T21:37:27.886-08:00</updated><title type='text'>Creative commercials</title><content type='html'>For your enjoyment, here's a site I've built recently: &lt;a href="http://creativecommercials.ning.com"&gt;Creative Commercials&lt;/a&gt; -- a (growing) collection of creative tv ads.&lt;br /&gt;&lt;br /&gt;Here are a couple I like:&lt;br /&gt;&lt;br /&gt;&lt;!-- Template Start: //templates/video/fragment_playerProper.php --&gt; &lt;embed src="http://creativecommercials.ning.com/flvplayer/flvplayer.swf" FlashVars="config_url=http%3A%2F%2Fcreativecommercials.ning.com%2Findex.php%2Fmain%2Fvideo%2FshowPlayerConfig%3Fid%3D2308008%26x%3D9T6UFaIOrM3M92jTpllD9SfRsk62uXKr&amp; &amp;fullscreen_btn=off&amp; &amp;app_link=on&amp;" width="450" height="390" scale="noscale" wmode="window" bgcolor="cccccc" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;/embed&gt; &lt;!-- Template End: //templates/video/fragment_playerProper.php --&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Template Start: //templates/video/fragment_playerProper.php --&gt; &lt;embed src="http://creativecommercials.ning.com/flvplayer/flvplayer.swf" FlashVars="config_url=http%3A%2F%2Fcreativecommercials.ning.com%2Findex.php%2Fmain%2Fvideo%2FshowPlayerConfig%3Fid%3D2327413%26x%3D9T6UFaIOrM3M92jTpllD9SfRsk62uXKr&amp; &amp;fullscreen_btn=off&amp; &amp;app_link=on&amp;" width="450" height="390" scale="noscale" wmode="window" bgcolor="cccccc" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;/embed&gt; &lt;!-- Template End: //templates/video/fragment_playerProper.php --&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-116330984787054688?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/116330984787054688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=116330984787054688' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/116330984787054688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/116330984787054688'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/11/creative-commercials.html' title='Creative commercials'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-116295228727638283</id><published>2006-11-07T16:51:00.000-08:00</published><updated>2006-11-07T18:19:36.863-08:00</updated><title type='text'>Extensible mod_rewrite with Lua</title><content type='html'>I was running an experiment with apache + mod_rewrite that required rules that cannot be expressed with regular expressions. mod_rewrite has the notion of &lt;span style="font-style:italic;"&gt;rewrite maps&lt;/span&gt;, which let you choose from a couple of built in functions (int:tolower, int:toupper, etc.) or a key-value pair map backed by a text or dbm file. &lt;br /&gt;&lt;br /&gt;Unfortunately, there's no way to plug in arbitrary mapping functions&lt;a href="#footnote"&gt;*&lt;/a&gt;, so my first thought was to extend mod_rewrite by adding a new built in function. This lets me write:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;LoadModule rewrite_module     modules/mod_rewrite.so&lt;br /&gt;RewriteEngine on&lt;br /&gt;RewriteMap foo  int:foo&lt;br /&gt;&lt;br /&gt;RewriteRule (.*) ${foo:$1} [L] &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;It works great, but this approach requires forking mod_rewrite.c, which is obviously not a good thing.&lt;br /&gt; &lt;br /&gt;Inspired by &lt;a href="http://kasparov.skife.org/blog/src/wombat/httpd-conf-cool.html"&gt;Brian's mod_wombat&lt;/a&gt;, which allows you write http handlers in Lua, I thought "wouldn't it be nice to be able to extend mod_rewrite with custom Lua scripts?". Say, something like:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;LoadModule rewrite_module     modules/mod_rewrite.so&lt;br /&gt;RewriteEngine on&lt;br /&gt;RewriteMap foo  lua:/usr/local/apache2/rewrite-rules.lua&lt;br /&gt;&lt;br /&gt;RewriteRule (.*) ${foo:$1} [L] &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;30 lines of code later, my lua-enabled mod_rewrite prototype is able to do exactly that. Mind you, this is a very crude implementation and doesn't check for errors, cache compiled scripts, etc. But all those details can be improved.&lt;br /&gt;&lt;br /&gt;Anyway, this is all becomes somewhat irrelevant with the latest version of mod_wombat, which allows you to define transform_name hooks in Lua, as well. &lt;br /&gt;&lt;br /&gt;It was a interesting experiment, nonetheless :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="footnote"&gt;*&lt;/a&gt; To be fair, there &lt;span style="font-style:italic;"&gt;is&lt;/span&gt; actually a way to do this, but I consider it to be too clunky and non-scalable to be of any value in a real production system. The mechanism consists on mod_rewrite talking to an external process that does translations via its stdin/stdout streams. As a result, a global mutex is required to guarantee correctness in the face of multiple simultaneous requests.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-116295228727638283?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/116295228727638283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=116295228727638283' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/116295228727638283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/116295228727638283'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/11/extensible-modrewrite-with-lua.html' title='Extensible mod_rewrite with Lua'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-114637416427421147</id><published>2006-04-29T22:09:00.000-07:00</published><updated>2006-04-29T22:22:31.453-07:00</updated><title type='text'>application/atom+xml content type workaround for Firefox</title><content type='html'>Here's a Firefox &lt;a href="http://utils.ning.com/firefox"&gt;extension&lt;/a&gt; that will let you view Atom 1.0 feeds inside your browser. Currently, Firefox does not understand the application/atom+xml content type and will treat the feed as a download and prompt you to save it or to open it with an external application. &lt;br /&gt;&lt;br /&gt;Once you install this extension, Atom feeds will be displayed in your browser like any other xml document.&lt;br /&gt;&lt;br /&gt;Get it &lt;a href="http://utils.ning.com/firefox/atom-workaround-0.1.xpi"&gt;here&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-114637416427421147?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/114637416427421147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=114637416427421147' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114637416427421147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114637416427421147'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/04/applicationatomxml-content-type.html' title='application/atom+xml content type workaround for Firefox'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-114574185914267087</id><published>2006-04-22T14:20:00.000-07:00</published><updated>2006-04-22T15:24:16.343-07:00</updated><title type='text'>Shoot Profiles</title><content type='html'>If you are into &lt;a href="http://clans.gameclubcentral.com/shoot"&gt;Shoot&lt;/a&gt; and games, you may appreciate this &lt;a href="http://shootprofiles.ning.com"&gt;application&lt;/a&gt; for uploading and sharing Shoot profiles. &lt;br /&gt;&lt;br /&gt;I uploaded the profiles from the &lt;a href="http://clans.gameclubcentral.com/shoot/profilelibrary.php"&gt;old site&lt;/a&gt; and added a few that I hadn't got around to posting. Feel free to &lt;a href="http://shootprofiles.ning.com/index.php/profiles/index/add"&gt;share&lt;/a&gt; yours!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-114574185914267087?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/114574185914267087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=114574185914267087' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114574185914267087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114574185914267087'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/04/shoot-profiles.html' title='Shoot Profiles'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-114438284492992801</id><published>2006-04-06T19:41:00.000-07:00</published><updated>2006-12-13T10:31:54.231-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Atom 1.0 parser for Ruby</title><content type='html'>I've been looking for a Ruby library for parsing &lt;a href="http://www.ietf.org/rfc/rfc4287"&gt;Atom 1.0&lt;/a&gt;. The only one I could find was &lt;a href="http://www.rubyforge.org/projects/feedtools"&gt;FeedTools&lt;/a&gt;. Unfortunately, it's intended to be a universal feed-parsing library and not quite what I need.&lt;br /&gt;&lt;br /&gt;As a result, I decided to build my own. The &lt;a href="http://www.rubyforge.org/projects/atom"&gt;project&lt;/a&gt; is hosted at RubyForge and the source code is available under the MIT license.&lt;br /&gt;&lt;br /&gt;It is still in its early stages, so don't expect much at this point. So far, it understands most atom:* elements and attributes but doesn't perform validation.&lt;br /&gt;&lt;br /&gt;The interface is fairly simple. For example, you can do this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;require 'atom'&lt;br /&gt;require 'net/http'&lt;br /&gt;require 'uri'&lt;br /&gt;&lt;br /&gt;str = Net::HTTP::get(URI::parse('http://blog.ning.com/atom.xml'))&lt;br /&gt;feed = Atom::Feed.new(str)&lt;br /&gt;&lt;br /&gt;feed.entries.each { |entry|&lt;br /&gt;   puts "'#{entry.title}' by #{entry.authors.first.name} on #{entry.published.strftime('%m/%d/%Y')}"&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Give it a try, play with it. Comments are welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-114438284492992801?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/114438284492992801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=114438284492992801' title='39 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114438284492992801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114438284492992801'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/04/atom-10-parser-for-ruby.html' title='Atom 1.0 parser for Ruby'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>39</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-114246946935554239</id><published>2006-03-15T16:22:00.000-08:00</published><updated>2006-12-13T10:32:24.780-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Where am I?</title><content type='html'>Need to get the name of the current method in Ruby?&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;module Kernel&lt;br /&gt;     def current_method&lt;br /&gt;          caller[0].sub(/.*`([^']+)'/, '\1').to_sym&lt;br /&gt;     end&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;irb(main):006:0&gt; def test&lt;br /&gt;irb(main):007:1&gt;    p current_method&lt;br /&gt;irb(main):008:1&gt; end&lt;br /&gt;=&gt; nil&lt;br /&gt;irb(main):009:0&gt; test&lt;br /&gt;:test&lt;br /&gt;=&gt; nil&lt;br /&gt;irb(main):010:0&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you want to get fancier, you can get get a reference to the method itself:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;module Kernel&lt;br /&gt;     def current_method&lt;br /&gt;          method(caller[0].sub(/.*`([^']+)'/, '\1').to_sym)&lt;br /&gt;     end&lt;br /&gt;end&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/9469017-114246946935554239?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/114246946935554239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=114246946935554239' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114246946935554239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/114246946935554239'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/03/where-am-i.html' title='Where am I?'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-113783312472816907</id><published>2006-02-21T23:30:00.000-08:00</published><updated>2006-02-21T23:35:12.953-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Design by contract for Ruby</title><content type='html'>Here's a nice little module &lt;a href="http://kasparov.skife.org/blog/"&gt;Brian&lt;/a&gt; and I hacked together a few weeks ago. It adds basic design by contract capabilities to classes with a fairly clean syntax (yay for Ruby's flexibility!)&lt;br /&gt;&lt;br /&gt;Take a look for yourself:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class Foo&lt;br /&gt;&amp;nbsp;&amp;nbsp;   include DesignByContract&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;     pre(:sqrt, "value must be &gt;= 0") { |v| v &gt;= 0 }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;   pre("divisor must be != 0") { |dividend, divisor| divisor != 0 }&lt;br /&gt;&amp;nbsp;&amp;nbsp;    post { |result, a, b| a - b * result &lt; 1e-3 }&lt;br /&gt;&amp;nbsp;&amp;nbsp;    def div(dividend, divisor)&lt;br /&gt;&amp;nbsp;&amp;nbsp;   &amp;nbsp;&amp;nbsp;    dividend / divisor&lt;br /&gt;&amp;nbsp;&amp;nbsp;  end&lt;br /&gt;  &lt;br /&gt;&amp;nbsp;&amp;nbsp;     def sqrt(value)&lt;br /&gt;&amp;nbsp;&amp;nbsp;   &amp;nbsp;&amp;nbsp;   Math.sqrt value&lt;br /&gt;&amp;nbsp;&amp;nbsp;     end&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;     post(:sqrt, "error is greater than expected") { |result, value| &lt;br /&gt;&amp;nbsp;&amp;nbsp;   &amp;nbsp;&amp;nbsp;   &amp;nbsp;&amp;nbsp;   result * result - value &lt; 1e-3 &lt;br /&gt;&amp;nbsp;&amp;nbsp;   }&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;When the DesignByContract module is included in a class, the &lt;em&gt;pre&lt;/em&gt; and &lt;em&gt;post&lt;/em&gt; methods become available. The parameters to these methods are a symbol representing the method to add the pre or post condition to, the message to print if the condition fails and a block that implements the condition.&lt;br /&gt;&lt;br /&gt;The method name and message are optional, though. If the method name is missing, the condition will applied to the first method definition following the pre/post declaration. Note that if the method name is present, the condition can be defined anywhere in the class definition, as shown in the example above. &lt;br /&gt;&lt;br /&gt;The condition block receives all the arguments passed to the method it applies to. They must return a boolean value indicating whether the condition succeeded. A minor difference between pre and post blocks is that the post block receives the result returned by the method as the first argument. This makes it possible to validate the results against the inputs such as in:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;post { |result, dividend, divisor| dividend - divisor * result &lt; 1e-3 }&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Get it &lt;a href="http://utils.ning.com/ruby/dbc.rb"&gt;here&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;How it works&lt;/h2&gt;&lt;br /&gt;In a nutshell, the pre and post methods intercept the existing method using the &lt;a href="http://split-s.blogspot.com/2006/01/replacing-methods.html"&gt;technique&lt;/a&gt; I described a few weeks ago (i.e., no poluting the class' namespace with aliased methods). The new methods test the provided condition before or after delegating the call to the original method and raise an exception if the condition fails.&lt;br /&gt;&lt;br /&gt;There is a small caveat, though. If pre/post are called &lt;em&gt;before&lt;/em&gt; the method is first created, it cannot be intercepted. To get around this the module uses an alternative trick. Whenever the module is included, it hooks into the method_added callback of class it's included into. If pre/post are called and the corresponding method does not exist, the interception is scheduled until the method is added.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-113783312472816907?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113783312472816907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113783312472816907' title='44 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113783312472816907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113783312472816907'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/02/design-by-contract-for-ruby.html' title='Design by contract for Ruby'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>44</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113817708549997327</id><published>2006-01-25T00:15:00.000-08:00</published><updated>2006-02-01T23:23:02.366-08:00</updated><title type='text'>Duplicate Message Remover for Thunderbird 1.5</title><content type='html'>I've updated the &lt;a href="http://split-s.blogspot.com/2005/02/duplicate-message-remover-01.html"&gt;Duplicate Message Remover&lt;/a&gt; extension to make it compatible with Thunderbird 1.5. Grab it &lt;a href="http://utils.ning.com/thunderbird/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-113817708549997327?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113817708549997327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113817708549997327' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113817708549997327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113817708549997327'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/01/duplicate-message-remover-for.html' title='Duplicate Message Remover for Thunderbird 1.5'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113783013059942162</id><published>2006-01-20T22:43:00.000-08:00</published><updated>2006-01-21T00:12:54.890-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Replacing methods</title><content type='html'>Let's say we want to replace a method instead of just &lt;a href="http://split-s.blogspot.com/2006/01/removing-methods-from-module.html"&gt;throwing it away&lt;/a&gt;. But we want the new method to be able to call the old implementation.&lt;br /&gt;&lt;br /&gt;The standard way of doing this is by aliasing the old method and making the new one call the aliased version:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;class Foo&lt;br /&gt;&amp;nbsp;&amp;nbsp;def method&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;class Foo&lt;br /&gt;&amp;nbsp;&amp;nbsp;alias :method :old_method&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;def method&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;old_method&lt;br /&gt;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This solution works perfectly for most situations, but what if we want to remove all traces of the old method?&lt;br /&gt;&lt;br /&gt;Here's a simple trick to do exactly that:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;class Foo&lt;br /&gt;&amp;nbsp;&amp;nbsp;  old_method = instance_method(:method)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;  define_method(:method) { |*args|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    # do something here ...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    old_method.bind(self).call(*args)&lt;br /&gt;&amp;nbsp;&amp;nbsp;  }&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;It shouldn't take much to understand how it works, but let's analyze it in more detail. The first line gets  a hold of the old implementation of &lt;span style="font-family: Courier New, Monospaced"&gt;method&lt;/span&gt;. &lt;span style="font-family: Courier New, Monospaced"&gt;instance_method&lt;/span&gt; returns an UnboundMethod object that wraps it.&lt;br /&gt;&lt;br /&gt;Next, we redefine &lt;span style="font-family: Courier New, Monospaced"&gt;method&lt;/span&gt; and pass it a block with the new implementation. One thing worth mentioning is that the &lt;span style="font-family: Courier New, Monospaced"&gt;old_method&lt;/span&gt; variable inside the block is bound to the variable assigned to outside of the block. The binding is maintained even after the execution reaches the end of the class definition. As a result, the new &lt;span style="font-family: Courier New, Monospaced"&gt;method&lt;/span&gt; has a direct reference to the old one... and nobody else does.&lt;br /&gt;&lt;br /&gt;After doing whatever it has to do, the new method calls the old one after binding the UnboundMethod to the current object (i.e., the object on which &lt;span style="font-family: Courier New, Monospaced"&gt;method&lt;/span&gt; was invoked). &lt;br /&gt;&lt;br /&gt;If you have a keen eye, you'll notice that there's something special about &lt;span style="font-family: Courier New, Monospaced"&gt;self&lt;/span&gt;. At first glance, it looks like a standard variable that just happens to hold a reference to the current object. If that were true, it would follow that the reference to &lt;span style="font-family: Courier New, Monospaced"&gt;self&lt;/span&gt; inside the block would be bound to the &lt;span style="font-family: Courier New, Monospaced"&gt;self&lt;/span&gt; representing class Foo. That is not the case, though. The binding of &lt;span style="font-family: Courier New, Monospaced"&gt;self&lt;/span&gt; is established when the block gets called.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-113783013059942162?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113783013059942162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113783013059942162' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113783013059942162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113783013059942162'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/01/replacing-methods.html' title='Replacing methods'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113756089736537717</id><published>2006-01-17T20:59:00.000-08:00</published><updated>2006-01-18T00:07:58.820-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Removing methods from a module</title><content type='html'>How do we remove a method from one of Ruby's built-in modules (Kernel, etc)? It should be easy and obvious, right? The following snippet should be enough, right?&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;#remove system from module Kernel&lt;br /&gt;Kernel.send :remove_method, :system    &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Well, not quite. While that prevents you from calling system() in the context of the current object, you can still invoke it like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;Kernel::system('date')&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;What's going on? &lt;br /&gt;&lt;br /&gt;It turns out that they way Kernel (and other built-in modules) are defined is analogous to doing the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;module Kernel&lt;br /&gt;&amp;nbsp;&amp;nbsp;def system (...)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;module_function :system&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Thus, system() is a method that will be added to instances of classes that &lt;em&gt;include&lt;/em&gt; the given module (in our case, instances of any object, since Kernel is included by Object), but it is also a method in Kernel's singleton class (bear with me for a moment), or a &lt;em&gt;module_method&lt;/em&gt; as the PickAxe book calls them. In Java parlance, they are simply static methods.&lt;br /&gt;&lt;br /&gt;Looking at Ruby's source code, we can see that all of Kernel's methods are defined by way of the &lt;em&gt;rb_define_module_function&lt;/em&gt; function, whose definition is:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;void&lt;br /&gt;rb_define_module_function(module, name, func, argc)&lt;br /&gt;&amp;nbsp;&amp;nbsp;VALUE module;&lt;br /&gt;&amp;nbsp;&amp;nbsp;const char *name;&lt;br /&gt;&amp;nbsp;&amp;nbsp;VALUE (*func)();&lt;br /&gt;&amp;nbsp;&amp;nbsp;int argc;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;rb_define_private_method(module, name, func, argc);&lt;br /&gt;&amp;nbsp;&amp;nbsp;rb_define_singleton_method(module, name, func, argc);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, what does it mean that "system" is a method of Kernel's singleton class? Let's recap what happens when we create a class and add a method to the singleton class of one of it's instances.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;class A&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;V1 = A.new &amp;nbsp;&amp;nbsp;    # creates an instance of A and assign it to constant V1&lt;br /&gt;V2 = A.new &amp;nbsp;&amp;nbsp;    # ... and V2&lt;br /&gt;&lt;br /&gt;# now we add method x() to V1's singleton class&lt;br /&gt;class &lt;&lt; V1&lt;br /&gt;&amp;nbsp;&amp;nbsp;   def x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      puts "hello"&lt;br /&gt;&amp;nbsp;&amp;nbsp;   end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;V1.x  &amp;nbsp;&amp;nbsp;        # will print "hello"&lt;br /&gt;V2.x  &amp;nbsp;&amp;nbsp;        # will fail ... V2 does not have a method x() &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Clear?&lt;br /&gt;&lt;br /&gt;Ok, now, remember that all Ruby modules are instances of a class called Module? Say we replace A by Module, V1 by Kernel and x() by system(). What we get is the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;Kernel = Module.new&lt;br /&gt;&lt;br /&gt;class &lt;&lt; Kernel&lt;br /&gt;&amp;nbsp;&amp;nbsp;    def system&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;       ...&lt;br /&gt;&amp;nbsp;&amp;nbsp;    end&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And that's essentially what's going on behind the scenes.&lt;br /&gt;&lt;br /&gt;Going back to the question that started this post, how do we remove a method from one of the built-in modules, anyway? The answer is easy, if not as obvious as we might have expected:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;module Kernel&lt;br /&gt;&amp;nbsp;&amp;nbsp;   remove_method :system&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class &lt;&lt; Kernel&lt;br /&gt;&amp;nbsp;&amp;nbsp;   remove_method :system&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Or, more concisely,&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;Kernel.send :remove_method, :system    &lt;br /&gt;class &lt;&lt; Kernel; self; end.send :remove_method, :system&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/9469017-113756089736537717?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113756089736537717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113756089736537717' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113756089736537717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113756089736537717'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/01/removing-methods-from-module.html' title='Removing methods from a module'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113693306343100571</id><published>2006-01-10T14:35:00.000-08:00</published><updated>2006-01-10T14:44:23.486-08:00</updated><title type='text'>Flying dog</title><content type='html'>LOL!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://video.google.com/videoplay?docid=2978884470072026171&amp;q=flying+dog"&gt;http://video.google.com/videoplay?docid=2978884470072026171&amp;q=flying+dog&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-113693306343100571?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113693306343100571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113693306343100571' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113693306343100571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113693306343100571'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2006/01/flying-dog.html' title='Flying dog'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-113529793342203944</id><published>2005-12-22T16:19:00.000-08:00</published><updated>2005-12-22T22:21:36.380-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby's executable class definitions</title><content type='html'>If you're coming to Ruby from Java, remember that class definitions are &lt;a href="http://split-s.blogspot.com/2005/02/definition-time-execution-time-anytime.html"&gt;executable&lt;/a&gt; code. I can think of at least one situation where this has practical implications and if you're not clear about it you'll spend a couple of hours banging your head against the wall.&lt;br /&gt;&lt;br /&gt;Consider this simple Java class:&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;class A&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;int a = 10;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;public int getA()&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return a;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If you create an object of type A and call it's method getA(), you'll get 10. No surprises here.&lt;br /&gt;&lt;br /&gt;Now, knowing that member variables in Ruby are prefixed with @ we go ahead and translate our little java class to Ruby like so:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;class A&lt;br /&gt;&amp;nbsp;&amp;nbsp;@a = 10&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;def a&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return @a&lt;br /&gt;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;We then create an object of class A and call its a() method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;irb(main):001:0&gt; class A&lt;br /&gt;irb(main):002:1&gt;   @a = 10&lt;br /&gt;irb(main):003:1&gt;   def a&lt;br /&gt;irb(main):004:2&gt;     return @a&lt;br /&gt;irb(main):005:2&gt;   end&lt;br /&gt;irb(main):006:1&gt; end&lt;br /&gt;=&gt; nil&lt;br /&gt;irb(main):007:0&gt; A.new.a&lt;br /&gt;=&gt; nil&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;"WTF!!" you say. Well, if you remembered what I said, class definitions are executable code. In our case, this means that the @a = 10 is executed when the class is defined, not when an instance of the class is created. As a result, this statement defines a member variable of the instance of class &lt;em&gt;Class&lt;/em&gt; that represents class A.&lt;br /&gt;&lt;br /&gt;To prove the last statment is true, let's make a() a class method:&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;class A&lt;br /&gt;&amp;nbsp;&amp;nbsp;@a = 10&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;def A.b&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return @a&lt;br /&gt;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;When we call it we get what we expected:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;irb(main):001:0&gt; class A&lt;br /&gt;irb(main):002:1&gt;   @a = 10&lt;br /&gt;irb(main):003:1&gt;   def A.a&lt;br /&gt;irb(main):004:2&gt;     return @a&lt;br /&gt;irb(main):005:2&gt;   end&lt;br /&gt;irb(main):006:1&gt; end&lt;br /&gt;=&gt; nil&lt;br /&gt;irb(main):007:0&gt; A.a&lt;br /&gt;=&gt; 10&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/9469017-113529793342203944?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113529793342203944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113529793342203944' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113529793342203944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113529793342203944'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/12/rubys-executable-class-definitions.html' title='Ruby&apos;s executable class definitions'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113527005833751701</id><published>2005-12-22T08:32:00.000-08:00</published><updated>2005-12-22T14:11:07.340-08:00</updated><title type='text'>Simple color effects</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/RGB"&gt;RGB&lt;/a&gt; is the most widespread method for representing colors. HTML, CSS, Java's java.awt.Color constructors, and countless more, all expect color to be described in terms of their RGB components. &lt;br /&gt;&lt;br /&gt;But RGB is not the best choice for doing common operations such as desaturation and certain types of gradients (e.g., shades of a color and fade to black or white). There's a much more natural way of manipulating colors for that purpose without going crazy with interpolation in the RGB color space. The trick is to work with the &lt;a href="http://en.wikipedia.org/wiki/HSV_color_space"&gt;HSV&lt;/a&gt; representation, instead. In the HSV space, a color is defined by it's hue (the "rainbow" of colors), it's saturation and it's brightness or value.&lt;br /&gt;&lt;br /&gt;For any given color, change the brightness to get a darker or lighter shade. If you want to desaturate it (without changing it's brightness), simply reduce it's saturation value.&lt;br /&gt;&lt;br /&gt;Here's a simple &lt;a href="http://clans.gameclubcentral.com/shoot/color.html"&gt;example&lt;/a&gt;, and the relevant Javascript code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;function RGB(r, g, b) &lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; this.r = r&lt;br /&gt;&amp;nbsp;&amp;nbsp; this.g = g&lt;br /&gt;&amp;nbsp;&amp;nbsp; this.b = b&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;RGB.prototype = {&lt;br /&gt;&amp;nbsp;&amp;nbsp; toHSV: function()&lt;br /&gt;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var max = Math.max(this.r, this.g, this.b)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var min = Math.min(this.r, this.g, this.b)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var s = (max - min) / max&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  switch (max) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case this.r: return new HSV(60 * (this.g - this.b) / (max - min), s, max)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case this.g: return new HSV(60 * (this.b - this.r) / (max - min) + 120, s, max)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case this.b: return new HSV(60 * (this.r - this.g) / (max - min) + 240, s, max)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  }&lt;br /&gt;&amp;nbsp;&amp;nbsp; },&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; toHex: function()&lt;br /&gt;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var r = Math.floor(this.r * 255).toString(16)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var g = Math.floor(this.g * 255).toString(16)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var b = Math.floor(this.b * 255).toString(16)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  return "#" + (r.length == 1? "0" : "") + r&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;             + (g.length == 1? "0" : "") + g&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;             + (b.length == 1? "0" : "") + b&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function HSV(h, s, v)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; this.h = h&lt;br /&gt;&amp;nbsp;&amp;nbsp; this.s = s&lt;br /&gt;&amp;nbsp;&amp;nbsp; this.v = v&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;HSV.prototype = {&lt;br /&gt;&amp;nbsp;&amp;nbsp; toRGB: function()&lt;br /&gt;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var sextant = Math.floor(this.h / 60) % 6&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var f = this.h / 60 - sextant&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  var p = this.v * (1 - this.s)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  q = this.v * (1 - f * this.s)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  t = this.v * (1 - (1 - f) * this.s)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  switch (sextant) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case 0: return new RGB(this.v, t, p)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case 1: return new RGB(q, this.v, p)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case 2: return new RGB(p, this.v, t)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case 3: return new RGB(p, q, this.v)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case 4: return new RGB(t, p, this.v)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   case 5: return new RGB(this.v, p, q)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  }&lt;br /&gt;&amp;nbsp;&amp;nbsp; },&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; toHex: function()&lt;br /&gt;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  return this.toRGB().toHex()&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function desaturate(box, color)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; box.style.backgroundColor = color.toHex()&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; color.s -= .01&lt;br /&gt;&amp;nbsp;&amp;nbsp; if (color.s &gt;= 0) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  window.setTimeout(function() { desaturate(box, color), 50 })&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function fadeToBlack(box, color)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; box.style.backgroundColor = color.toHex()&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; color.v -= .01&lt;br /&gt;&amp;nbsp;&amp;nbsp; if (color.v &gt;= 0) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  window.setTimeout(function() { fadeToBlack(box, color), 50 })&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function fadeToWhite(box, color)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;        box.style.backgroundColor = color.toHex()&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;        var v = 1 - color.v&lt;br /&gt;&amp;nbsp;&amp;nbsp;        var distance = Math.sqrt(color.s * color.s + v * v)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;        color.s -= 0.01 * color.s / distance&lt;br /&gt;&amp;nbsp;&amp;nbsp;        color.v += 0.01 * v / distance&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;        if (color.v &lt;= 1 &amp;&amp; color.s &gt;= 0) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;                window.setTimeout(function() { fadeToWhite(box, color), 50 })&lt;br /&gt;&amp;nbsp;&amp;nbsp;        }&lt;br /&gt;}&lt;br /&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/9469017-113527005833751701?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113527005833751701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113527005833751701' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113527005833751701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113527005833751701'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/12/simple-color-effects.html' title='Simple color effects'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113521142621016119</id><published>2005-12-21T16:22:00.000-08:00</published><updated>2005-12-21T17:44:55.736-08:00</updated><title type='text'>Internationalized GET parameters with Tomcat</title><content type='html'>One tiny, oft overlooked detail when working with internationalized web apps is that the Content-Type header specifies the type and encoding of the &lt;span style="font-weight:bold;"&gt;body&lt;/span&gt; of the http request. &lt;br /&gt;&lt;br /&gt;Say you want to add searching to your site, which is implemented as a form that submits using method="GET", and your target audience is Japanese people. How do you deal with internationalized query parameters, considering that GET requests do not have a body? &lt;br /&gt;&lt;br /&gt;Historically, query strings were expected to contain characters in the ISO-8859-1 character set, with anything but a subset of ASCII encoded using the %xx notation. In discussions a few years ago it was agreed that using UTF-8 encoding for international characters was the best alternative. This is reflected in &lt;a href="http://www.gbiv.com/protocols/uri/rfc/rfc3986.html"&gt;RFC 3986&lt;/a&gt; (which is backed by the &lt;a href="http://www.w3.org/International/O-URL-and-ident.html"&gt;W3C&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;em&gt;&lt;br /&gt;When a new URI scheme defines a component that represents textual data consisting of characters from the Universal Character Set [UCS], the data should first be encoded as octets according to the UTF-8 character encoding [STD63]; then only those octets that do not correspond to characters in the unreserved set should be percent-encoded. For example, the character A would be represented as "A", the character LATIN CAPITAL LETTER A WITH GRAVE would be represented as "%C3%80", and the character KATAKANA LETTER A would be represented as "%E3%82%A2".&lt;/em&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;If you're running Tomcat, watch out! If your URL contains unicode characters, the browser will properly encode them as UTF-8 and then do the %xx magic for each byte. Tomcat will treat each encoded byte in the UTF-8 representation as a single ISO-8859-1 character and make your Japanese users very unhappy.&lt;br /&gt;&lt;br /&gt;Unfortunately, this is Tomcat's default behavior. Fortunately, there is server configuration option that will force it to treat URLs as per RFC 3986. To enable it, edit server.xml and add the following parameter to the &lt;span style="font-style:italic;"&gt;connector&lt;/span&gt; element:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&amp;lt;Server ...&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;Service ...&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Connector ... &lt;span style="font-weight:bold;"&gt;URIEncoding="UTF-8"&lt;/span&gt;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/Connector&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/Service&amp;gt;&lt;br /&gt;&amp;lt;/Server&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;BTW, I've tested this in Tomcat 5.5.12. I don't know whether it will work in previous versions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-113521142621016119?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113521142621016119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113521142621016119' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113521142621016119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113521142621016119'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/12/internationalized-get-parameters-with.html' title='Internationalized GET parameters with Tomcat'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113470776156261769</id><published>2005-12-15T20:28:00.000-08:00</published><updated>2005-12-15T21:04:39.483-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>ANTLR for Ruby</title><content type='html'>The latest release of &lt;a href="http://www.antlr.org/download/antlr-3.0ea7.tar.gz"&gt;ANTLR v3&lt;/a&gt; adds support for Ruby as a target language, courtesy of yours truly. Let's look at an example to see what's possible.&lt;br /&gt;&lt;br /&gt;The following grammar generates a parser that can evaluate simple arithmetic expressions involving integer numbers, +, -, *, /, ( and ).&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;grammar Calculator;&lt;br /&gt;options {&lt;br /&gt;&amp;nbsp;&amp;nbsp;language = Ruby;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@members {&lt;br /&gt;&amp;nbsp;&amp;nbsp;@stack = []&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;def result&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@stack[0]&lt;br /&gt;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;parse: expression;&lt;br /&gt;&lt;br /&gt;expression: mult (&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'+' mult {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@stack.push(@stack.pop + @stack.pop)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;|  '-' mult {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a = @stack.pop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b = @stack.pop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@stack.push(b - a)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;)* ;&lt;br /&gt;&lt;br /&gt;mult:   atom (&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'*' atom {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@stack.push(@stack.pop * @stack.pop)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;|  '/' atom {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a = @stack.pop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b = @stack.pop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@stack.push(b / a.to_f)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;)* ;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;atom: n=NUMBER { @stack.push($n.text.to_i) }&lt;br /&gt;&amp;nbsp;&amp;nbsp;| '(' expression ')';&lt;br /&gt;&lt;br /&gt;NUMBER: ('0'..'9')+;&lt;br /&gt;&lt;br /&gt;WS: (' ' | '\n' | '\t')+ { channel = 99 };&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;First, we need to process the grammar with ANTLR. You'll need to have Java installed in order to do this. ANTLR will generate two files: Calculator.rb and CalculatorLexer.rb.&lt;br /&gt;&lt;br /&gt;You'll also need the ANTLR ruby runtime library (just a small .rb file) which you can get &lt;a href="http://clans.gameclubcentral.com/shoot/antlr.rb"&gt;here&lt;/a&gt;. Just drop into the same directory as the two .rb files created above (in the future I may package it as a gem).&lt;br /&gt;&lt;br /&gt;We got our parser, so let's try it out. Create another ruby file with the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;require 'Calculator'&lt;br /&gt;require 'CalculatorLexer'&lt;br /&gt;&lt;br /&gt;lexer = CalculatorLexer.new(ANTLR::CharStream.new(STDIN))&lt;br /&gt;parser = Calculator.new(ANTLR::TokenStream.new(lexer))&lt;br /&gt;parser.parse&lt;br /&gt;&lt;br /&gt;puts parser.result&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now, run the program, type an expression and press CTRL-D (or CTRL-Z if in Windows) to see the results, like so:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(5 + 4) * (10 - 2) / 3&lt;br /&gt;^Z&lt;br /&gt;24.0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Simple... but cool, eh?&lt;br /&gt;&lt;br /&gt;ANTLR v3 is still in pre-alpha stage, and the Ruby backend is a work in progress. So far, it can handle syntactic and semantic predicates, token labels, etc. and I'm planning to add support for scopes and token/rule parameters and return values next. AST creation will come after that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-113470776156261769?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113470776156261769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113470776156261769' title='58 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113470776156261769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113470776156261769'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/12/antlr-for-ruby.html' title='ANTLR for Ruby'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>58</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-113300039848212129</id><published>2005-11-26T01:03:00.000-08:00</published><updated>2005-11-26T02:21:36.006-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>ANTLR-based Ruby grammar</title><content type='html'>It looks like &lt;a href="http://moonbase.rydia.net/mental/blog/programming/the-ruby-grammar-project.html"&gt;other people&lt;/a&gt; are showing interest in replacing the YACC-based Ruby parser by one based on ANTLR. This hits close to a project I've been working on in my spare time.&lt;br /&gt;&lt;br /&gt;When I looked at JRuby's source code a few weeks ago, I thought I'd start trying to understand how the parser works. I had a few ideas I wanted to experiment with, but... &lt;br /&gt;&lt;br /&gt;The YACC-based parser is too hard to fathom. There are too many scattered pieces with no clear dependencies. Making changes without breaking things should be even harder. &lt;br /&gt;&lt;br /&gt;So I decided to start working on ANTLR-based grammar to replace the current implementation -- pretty much what &lt;a href="http://moonbase.rydia.net/"&gt;MenTaLguY&lt;/a&gt; is trying to do. I'm still in experimentation mode and trying to figure out how I'll deal with some of the features of Ruby that are not usually found in other languages.&lt;br /&gt;&lt;br /&gt;One of the hardest aspects, I think, is how to parse %Q-delimited strings. Here's how they work (from the Pickaxe book): &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Following the type character is a delimiter, which can be any nonalphabetic or nonmultibyte&lt;br /&gt;character. If the delimiter is one of the characters (, [, {, or &lt;, the literal&lt;br /&gt;consists of the characters up to the matching closing delimiter, taking account of nested&lt;br /&gt;delimiter pairs. For all other delimiters, the literal comprises the characters up to the&lt;br /&gt;next occurrence of the delimiter character.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Additionally, %Q strings can contain #{} constructs, whose contents should be parsed as Ruby expressions. These can probably be handled in a manner similar to how this grammar for the &lt;a href="http://www.erights.org/e-impls/e-on-e/egrammar/"&gt;E language&lt;/a&gt; implements what they call &lt;em&gt;quasi-literals&lt;/em&gt;. &lt;br /&gt;&lt;br /&gt;I haven't yet decided on how to deal with delimiters but I have the feeling it may require writing a custom lexer for string contexts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-113300039848212129?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/113300039848212129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=113300039848212129' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113300039848212129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/113300039848212129'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/11/antlr-based-ruby-grammar.html' title='ANTLR-based Ruby grammar'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-112881319832546050</id><published>2005-10-08T16:06:00.000-07:00</published><updated>2005-10-08T16:13:25.473-07:00</updated><title type='text'>Firefox search plugins for Ning</title><content type='html'>If you're using Firefox, you can get a few search plugins for Ning here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://utils.ning.com/plugin/"&gt;http://utils.ning.com/plugin/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-112881319832546050?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/112881319832546050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=112881319832546050' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/112881319832546050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/112881319832546050'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/10/firefox-search-plugins-for-ning.html' title='Firefox search plugins for Ning'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-112853379341839955</id><published>2005-10-05T10:07:00.000-07:00</published><updated>2005-10-05T10:36:33.426-07:00</updated><title type='text'>It's aliiiive!</title><content type='html'>A couple of days ago we launched &lt;a href="http://www.ning.com"&gt;Ning&lt;/a&gt;, a playground for building social applications. Lots of work in the past few months -- that's my lame excuse for not having posted this long :) --, working &lt;a href="http://www.sklar.com/blog"&gt;with&lt;/a&gt; a &lt;a href="http://www.dynamicobjects.com/d2r"&gt;great&lt;/a&gt; &lt;a href="http://www.bitsplitter.net/blog"&gt;team&lt;/a&gt; (and others that don't have a blog to link to).&lt;br /&gt;&lt;br /&gt;The next few months are going to be exciting!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-112853379341839955?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/112853379341839955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=112853379341839955' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/112853379341839955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/112853379341839955'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/10/its-aliiiive.html' title='It&apos;s aliiiive!'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-111179146333171731</id><published>2005-03-25T14:44:00.000-08:00</published><updated>2005-03-25T14:57:43.333-08:00</updated><title type='text'>Goodbye Texas, hello California</title><content type='html'>split-s has been silent lately. A lot has been happening in recent weeks, and my mind has been elsewhere.&lt;br /&gt;&lt;br /&gt;I'm leaving my current job in Plano and moving to the Bay Area. I can't say what I'll be doing, yet. &lt;a href="http://www.dynamicobjects.com/d2r/archives/003072.html"&gt;Stealth-mode and all that&lt;/a&gt; :). All I'll say for now is that I'll be working with &lt;a href="http://www.dynamicobjects.com/d2r"&gt;Diego&lt;/a&gt; and a few other great people.&lt;br /&gt;&lt;br /&gt;Now, to start planning for the move. It's gonna be very hectic for the next few weeks, but I'm excited!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-111179146333171731?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/111179146333171731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=111179146333171731' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/111179146333171731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/111179146333171731'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/03/goodbye-texas-hello-california.html' title='Goodbye Texas, hello California'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-111030228455083811</id><published>2005-03-08T08:58:00.000-08:00</published><updated>2005-03-08T09:25:54.693-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>const_missing</title><content type='html'>There's an ongoing weekly quiz in the Ruby mailing list. This week's theme is roman numerals -- writing a program that can read roman numerals from the standard input and print out their arabic representation. A few solutions have been posted, standard stuff. But Dave Burt &lt;a href="http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/133160"&gt;complemented&lt;/a&gt; his with a very neat hack. He makes it possible to treat integers and roman numerals interchangeably, and to perform arithmetic operations with them:&lt;br /&gt;&lt;br /&gt;VII + 3 -&gt; X&lt;br /&gt;XIV / 2 -&gt; VII&lt;br /&gt;VIII.divmod(III) -&gt; [II, II]&lt;br /&gt;etc.&lt;br /&gt;&lt;br /&gt;Part of this is achieved by redefining the const_missing method of the Object class, which kicks in whenever the interpreter finds reference to an unknown constant.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def Object.const_missing sym&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# verify that the constant is a roman numeral&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise NameError.new("uninitialized constant: #{sym}") unless RomanNumerals::REGEXP === sym.to_s&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# define the constant and return it&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const_set(sym, RomanNumeral.get(sym))&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The arithmetic operations are made possible by redefining RomanNumeral's method_missing method with code that delegates unknown operations to the it's integer representation. &lt;br /&gt;&lt;br /&gt;Take a &lt;a href="http://www.dave.burt.id.au/ruby/roman_numerals.rb"&gt;peek&lt;/a&gt; at the complete solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-111030228455083811?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/111030228455083811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=111030228455083811' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/111030228455083811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/111030228455083811'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/03/constmissing.html' title='const_missing'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110978772301426518</id><published>2005-03-02T10:21:00.000-08:00</published><updated>2005-03-02T10:27:13.356-08:00</updated><title type='text'>Stealth fighter jet unveiled</title><content type='html'>&lt;a href="http://www.zeeb.at/oops/show.php?file=Stealth fighter.jpg"&gt;See&lt;/a&gt; for yourself...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I had a good laugh with these, too. Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.zeeb.at/oops/show.php?file=DamnGoodTailHook.jpg"&gt;1&lt;/a&gt; &lt;a href="http://www.zeeb.at/oops/show.php?file=Fill-er-up.jpg"&gt;2&lt;/a&gt; &lt;a href="http://www.zeeb.at/oops/show.php?file=ForecastingStone.jpg"&gt;3&lt;/a&gt; &lt;a href="http://www.zeeb.at/oops/show.php?file=Nothing_Changes.jpg"&gt;4&lt;/a&gt; &lt;a href="http://www.zeeb.at/oops/show.php?file=SpeedEnforcement1.jpg"&gt;5&lt;/a&gt; &lt;a href="http://www.zeeb.at/oops/show.php?file=SpeedEnforcement2.jpg"&gt;6&lt;/a&gt; &lt;a href="http://www.zeeb.at/oops/show.php?file=WindowsPanel.jpg"&gt;7&lt;/a&gt; &lt;a href="http://www.zeeb.at/oops/show.php?file=wyoming_windsock.jpg"&gt;8&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110978772301426518?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110978772301426518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110978772301426518' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110978772301426518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110978772301426518'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/03/stealth-fighter-jet-unveiled.html' title='Stealth fighter jet unveiled'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110926507817801824</id><published>2005-02-24T09:05:00.000-08:00</published><updated>2005-02-24T09:36:25.943-08:00</updated><title type='text'>Ruby-style iterators in Java</title><content type='html'>Loop abstraction is probably the most common application of &lt;a href="http://split-s.blogspot.com/2005/02/building-blocks.html"&gt;blocks&lt;/a&gt; in Ruby. The idea being that the programmer should not have to deal with the iteration code itself and concentrate on what needs to be done at each step, instead. And it's typically a good idea.&lt;br /&gt;&lt;br /&gt;This is what a standard pre-Java 5 iteration looks like:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;Iterator i = collection.iterator();&lt;br /&gt;while (i.hasNext()) {&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;Object obj = i.next();&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Or, for iterating over an array:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;for (int i = 0; i &lt; array.length; ++i) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object obj = array[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;These are cleary prone to cause programming errors. Forget to call i.next(), call it twice, use &amp;lt;= instead of &amp;lt;, forget ++, and all goes to hell.&lt;br /&gt;&lt;br /&gt;Iterators have gotten significantly better in Java 5 with the introduction of the &lt;em&gt;for each&lt;/em&gt; construct, but they are still a long way from Ruby's internal iterators:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;for (String str : listOfStrings) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;A little bit of nomenclature here. External iterators are those where the client code controls how the iteration takes place (e.g., the Java way). Internal iterators, on the other hand, abstract that logic and only require the client code to supply the action to perform at each step of the iteration (e.g., the Ruby way). &lt;br /&gt;&lt;br /&gt;Take a look at the iterator idiom in Ruby:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;array.each { |value|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Much cleaner, and no need for so much boilerplate, don't you think?&lt;br /&gt;&lt;br /&gt;In the majority of cases, what a program really needs are internal iterators. From a code reuse perspective, why replicate the same construct over and over? But make no mistake, there are some legitimate cases for where external iterators are necessary, such as when looping over several collections in parallel (try doing that with internal iterators).&lt;br /&gt;&lt;br /&gt;Ruby provides a way for &lt;em&gt;externalizing&lt;/em&gt; internal iterators. Using the Generator class, an Enumerable object (i.e., that which exposes a method &lt;em&gt;each&lt;/em&gt;) can be transformed into an external iterator:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;generator = Generator.new [1,2,3,4,5,6,7]&lt;br /&gt;&lt;br /&gt;while generator.next?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts generator.next&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Internal iterators in Java&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, how about internal iterators for Java? The first thing we need to look at is how to encapsulate a chunk of code in a form that can be passed around (a la Ruby blocks).&lt;br /&gt;&lt;br /&gt;The closest we can get are anonymous inner classes, but it's not even fair to compare them with Ruby blocks. The latter a lot more flexible, without the clunky syntax. Here's an how we could emulate a general-purpose block in Java 5:&lt;br /&gt; &lt;br /&gt;&lt;div class="code"&gt;interface Block {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    Object call(Object... items);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;void methodThatTakesBlock(Block block)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    block.call("hello", "world");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Block block = new Block() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    Object call(Object... items) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        return items[0].toString() + items[1].toString();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;methodThatTakesBlock(block);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;First, you'll notice we're declaring a Block interface. This is needed in order to be able to invoke the "call" method on the block (it would be possible to do via reflection, too, but that's another story).&lt;br /&gt;&lt;br /&gt;The use of varargs helps avoid having to declare a block class or method for each possible combination of arguments and return values, but places the burden of extracting the arguments from the array on the implementer of the block.&lt;br /&gt;&lt;br /&gt;For what we're trying to achieve here, we're going to stick with non-vararg arguments. In fact, our block only needs one argument, namely, the element that's being iterated over at each step. Here it goes:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;interface IterationCallback&amp;lt;E&amp;gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        void call(E element);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface EnumerableCollection&amp;lt;E&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;extends Collection&lt;E&gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; void each(IterationCallback&amp;lt;E&amp;gt; callback);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class EnumerableArrayList&amp;lt;E&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    extends ArrayList&amp;lt;E&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    implements EnumerableCollection&amp;lt;E&amp;gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        public void each(IterationCallback&amp;lt;E&amp;gt; callback)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;                for (E element : this) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;                        callback.call(element);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;                }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        }&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;And here's how to use it:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;EnumerableCollection&amp;lt;Integer&amp;gt; list = new EnumerableArrayList&amp;lt;Integer&amp;gt;();&lt;br /&gt;&lt;br /&gt;            list.add(1);&lt;br /&gt;            list.add(2);&lt;br /&gt;            list.add(3);&lt;br /&gt;            list.add(4);&lt;br /&gt;            list.add(5);&lt;br /&gt;&lt;br /&gt;            list.each(new IterationCallback&amp;lt;Integer&amp;gt;() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    public void call(Integer element) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    System.out.println(element);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   }&lt;br /&gt;            });&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;So, it is possible, but nobody said it would be pretty. Better language support would be needed to make internal iterators as developer-friendly as they are in Ruby. And we're not even considering the performance implications. The above code instantiates an extra object compared to using Java's iterator idiom, and requires an extra method call. It could have significant impact if used in the wrong place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110926507817801824?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110926507817801824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110926507817801824' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110926507817801824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110926507817801824'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/ruby-style-iterators-in-java.html' title='Ruby-style iterators in Java'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110857007106858592</id><published>2005-02-20T13:40:00.000-08:00</published><updated>2005-02-20T13:58:29.733-08:00</updated><title type='text'>Do-not-call registry loophole?</title><content type='html'>I received a call last Friday at home. I was at work, but the answering maching picked it up. The message said:&lt;br /&gt;&lt;blockquote&gt;... This is not a sales call or a solicitation. Unfortunately, due to the nature of this matter, I am not able to provide additional information in this format. I, or one of my associates, can be reached at 1-800-XXX-XXXX. Please return this call..."&lt;br /&gt;&lt;/blockquote&gt;I used to get marketing calls every day, even Saturdays at 8 am. Really annoying. When I registered my phone number with the FCC do-not-call list over a year ago, the calls stopped. The rule does not limit some kinds of calls, though. To quote from the &lt;a href="http://www.fcc.gov/cgb/donotcall/"&gt;FCC&lt;/a&gt; site:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;calls from organizations with which you have established a business relationship&lt;br /&gt;&lt;li&gt;calls for which you have given prior written consent&lt;br /&gt;&lt;li&gt;calls which are not commercial or do not include unsolicited advertisements&lt;br /&gt;&lt;li&gt;calls by or on behalf of tax-exempt non-profit organizations&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;It seems to me that by saying "this is not a sales call or solicitation" they are attempting to cover themselves (see the 3rd item above). And if I call them back, then it would be me who's contacting them, so they would be exempted from the rule and free to try to sell me anything.&lt;br /&gt;&lt;br /&gt;I'm not calling them back, of course. But I hope this is not the beginning of a trend, or I may have to start shutting off my phone every Friday night... again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110857007106858592?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110857007106858592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110857007106858592' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110857007106858592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110857007106858592'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/do-not-call-registry-loophole.html' title='Do-not-call registry loophole?'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110886997523197549</id><published>2005-02-19T17:47:00.000-08:00</published><updated>2005-02-20T11:41:45.343-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>building blocks</title><content type='html'>One of the features I like best in Ruby is the support for &lt;em&gt;blocks&lt;/em&gt;. Blocks are, essentially, chunks of code that can be passed around as objects and invoked at a later point in the program (also known as &lt;em&gt;lambdas&lt;/em&gt; in other languages). But they are more than just code. When a block is defined, the context in which it is defined (variables, constants, etc) goes with it.&lt;br /&gt;&lt;br /&gt;You define a block like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;b = lambda { |value| puts value }&lt;br /&gt;&lt;br /&gt;c = lambda do |value|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;              puts value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;           end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Either {} or do...end can be used as delimiters. The names between | are the arguments to the block. Any number of arguments can be specified by separating them with comma: |value, i, j|&lt;br /&gt;&lt;br /&gt;To call the block:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;b.call("hello")&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The need for &lt;em&gt;call&lt;/em&gt; &lt;a href="http://redhanded.hobix.com/inspect/functionCall.html"&gt;may go  away&lt;/a&gt;, though.&lt;br /&gt;&lt;br /&gt;A little syntactic sugar allows us to pass blocks to methods implicitly. As far as I know, this syntax originated as a way to abstract looping behavior, one of the key applications of blocks in Ruby.&lt;br /&gt;&lt;br /&gt;This is how it works:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;   methodThatTakesBlock { |value| puts value }&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Sweet, eh?&lt;br /&gt;&lt;br /&gt;A method that takes a block can refer to it implicitly or explicitly. Implicitly:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def methodThatTakesBlock &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   yield "hello"&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The key here is the &lt;em&gt;yield&lt;/em&gt; keyword, which calls the provided block with one or more values as arguments. &lt;em&gt;yield&lt;/em&gt; can be called any number of times, for example:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def methodThatTakesBlock &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  yield "hello"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  yield "world"&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;But what if you need to keep a reference to the block, or pass the block around from within that method? Easy. If the last parameter in a method declaration is prefixed with &amp;amp;, the provided block will be assigned to the parameter. Take a look for yourself:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class BlockContainer&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    def initialize&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        @blocks = {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    end&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    def addBlock(name, &amp;block)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        @blocks[name] = block&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;container = BlockContainer.new&lt;br /&gt;container.addBlock("a") { puts "a" }&lt;br /&gt;container.addBlock("b") { puts "b" }&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Going back to what I said about blocks taking the context they were defined in with them... it is true! I swear! &lt;br /&gt;&lt;br /&gt;Ok, to illustrate the idea, look a this code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def methodThatTakesBlock&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    yield&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;a = 1&lt;br /&gt;methodThatTakesBlock { puts a }&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Your first reaction might be "that won't work, &lt;em&gt;a&lt;/em&gt; will not be available from within &lt;em&gt;methodThatTakesBlock&lt;/em&gt;". In fact, it will, simply because &lt;em&gt;a&lt;/em&gt; is part of the context where the block is defined.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110886997523197549?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110886997523197549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110886997523197549' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110886997523197549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110886997523197549'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/building-blocks.html' title='building blocks'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110792986872704089</id><published>2005-02-10T08:00:00.000-08:00</published><updated>2005-02-09T08:04:56.083-08:00</updated><title type='text'>astronaut monkeys?</title><content type='html'>Cedric &lt;a href="http://beust.com/weblog/archives/000241.html"&gt;suggests&lt;/a&gt; that the inconsistencies in Java 5 collections are there to preserve compatibility. Until I see an example, I won't be conviced (nudge, nudge...) ;)&lt;br /&gt;&lt;br /&gt;Unless I'm way off base, binary compatibility wouldn't be broken. For an inside look, see &lt;a href="http://www.jroller.com/page/eu/20050209#bytecode_tales_erasure_of_collection"&gt;Euxx&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;After all, the runtime signature for &lt;br /&gt;&lt;span style="font-family:Courier"&gt;boolean remove(E element)&lt;/span&gt; is &lt;span style="font-family:Courier"&gt;boolean remove(Object element)&lt;/span&gt; and for &lt;span style="font-family:Courier"&gt;E[] toArray()&lt;/span&gt; it's &lt;span style="font-family:Courier"&gt;Object[] toArray()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Source compatibility is not broken, either. If you're doing stuff like:&lt;br /&gt;&lt;br /&gt;List list = new ArrayList();&lt;br /&gt;list.add("hello");&lt;br /&gt;list.remove(new Integer(1));&lt;br /&gt;&lt;br /&gt;your code will still compile in Java 5.&lt;br /&gt;&lt;br /&gt;And if you want to take advantage of generics, well, you have to abide by the new rules. Is that too much to ask for?&lt;br /&gt;&lt;br /&gt;I'm starting to think &lt;a href="http://www.dynamicobjects.com/d2r/archives/003108.html"&gt;astronaut monkeys&lt;/a&gt; may be the culprits ;)&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110792986872704089?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110792986872704089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110792986872704089' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110792986872704089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110792986872704089'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/astronaut-monkeys.html' title='astronaut monkeys?'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110749052559216788</id><published>2005-02-07T11:28:00.000-08:00</published><updated>2005-02-07T14:24:31.880-08:00</updated><title type='text'>Java 5 Collections inconsistencies</title><content type='html'>Generics are one of the Cool New Features&amp;trade; in Java 5. The collections framework has been ported to make use of the new syntax and semantics. So now it's possible to do the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;List&amp;lt;String&amp;gt; list = new Array&amp;lt;String&amp;gt;();&lt;br /&gt;&lt;br /&gt;list.add("hello");&lt;br /&gt;list.add("world");&lt;br /&gt;&lt;br /&gt;String hello = list.get(0);&lt;br /&gt;String world = list.get(1);&lt;br /&gt;&lt;br /&gt;for (String str : list) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   System.out.println(str.length());&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;There are definite advantages to the generics-enabled syntax. It looks *much* cleaner for starters. And we can combine them with the new for each syntax for a nicer looking loop construct. Compare the above with pre-Java 5 code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;List list = new ArrayList(); &lt;br /&gt;&lt;br /&gt;list.add("hello");&lt;br /&gt;list.add("world");&lt;br /&gt;&lt;br /&gt;String hello = (String) list.get("hello"); // downcast needed here!&lt;br /&gt;String world = (String) list.get("world");&lt;br /&gt;&lt;br /&gt;// this is plain ugly...&lt;br /&gt;Iterator i = list.iterator();&lt;br /&gt;while (i.hasNext()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   String element = (String) e.next();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   System.out.println(element.length());&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;But a couple of aspects of the new generics-enabled collections framework annoy me. For example, the Collections interface is declared as &lt;span style="font-family:Courier"&gt;Collection&amp;lt;E&amp;gt;&lt;/span&gt; and the &lt;span style="font-family:Courier"&gt;add&lt;/span&gt; method, for example, is correctly declared as:&lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;boolean add(E object)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So I cannot help but wonder why, then, is &lt;span style="font-family:Courier"&gt;remove&lt;/span&gt; declared as:&lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;boolean remove(Object object)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This declaration makes it possible to call &lt;span style="font-family:Courier"&gt;remove&lt;/span&gt; with an element of the wrong type. While it won't trigger an exception, it could hide a coding error. For example, in the snippet below we "forget" to call &lt;span style="font-family:Courier"&gt;toString()&lt;/span&gt; on &lt;span style="font-family:Courier"&gt;x&lt;/span&gt;. Yet, we don't get a compilation or runtime error. We can only realize there's a mistake when the program does not produce the expected results.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;String&amp;gt;();&lt;br /&gt;&lt;br /&gt;list.add("hello");&lt;br /&gt;list.add("1");&lt;br /&gt;...&lt;br /&gt;Integer x = new Integer(1);&lt;br /&gt;list.remove(x);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Similarly, the toArray() method should be declared as follows:&lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;E[] toArray()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Instead of:&lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;Object[] toArray()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Othewise, we need to downcast the result of the call, as shown in the example below... yuck! But most importantly, it allows invalid down casts, which is one of the things generics try to help avoid in the first place.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;List&lt;String&gt; list = new ArrayList&lt;String&gt;();&lt;br /&gt;&lt;br /&gt;list.add("hello");&lt;br /&gt;&lt;br /&gt;Object[] elements = list.toArray();&lt;br /&gt;&lt;br /&gt;String string = (String) elements[0]; // downcast needed&lt;br /&gt;Integer intValue = (Integer) elements[0]; // accepted by compiler, but fails at runtime.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Lastly, there's another variation of the toArray method, which has been defined as: &lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;&amp;lt;T&amp;gt; T[] toArray(T[] type)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here the method uses generics, but there's a caveat. If T is not a supertype of E, an ArrayStoreException will be thrown at runtime. It would be nice to be able to capture the relationship between T and E as in the example below. Unfortunately, such syntax is not allowed:&lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;&amp;lt;T super E&amp;gt; T[] toArray(T[] type)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I don't know what were the reasons behind these choices, and I certainly hope it wasn't a case of "oops, I missed it"-itis. For performance, maybe (the compiler would save a downcast)? If that was it, it wasn't a good trade-off, IMO.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; fixed an error in one of the code snippets. Thanks for the observation, &lt;a href="http://www.dynamicobjects.com/d2r"&gt;Diego&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110749052559216788?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110749052559216788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110749052559216788' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110749052559216788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110749052559216788'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/java-5-collections-inconsistencies.html' title='Java 5 Collections inconsistencies'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110754639906330104</id><published>2005-02-04T11:31:00.000-08:00</published><updated>2006-02-04T11:43:23.893-08:00</updated><title type='text'>Duplicate Message Remover 0.1</title><content type='html'>Here's the extension for Thunderbird I was &lt;a href="http://split-s.blogspot.com/2005/02/two-of-each.html"&gt;working on&lt;/a&gt;. It removes duplicate messages in any given folder and moves them into the Trash (the operation can be undone). The function can be accessed by right clicking on a folder and selecting "Delete Duplicate Messages".&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Installation instructions&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://clans.gameclubcentral.com/shoot/thunderbird/deleteduplicates.xpi"&gt;Download&lt;/a&gt; the extension to your computer (Right-click on the link, and choose "Save Link As" if you're using Firefox. Otherwise, Firefox may try to install it itself)&lt;br /&gt;&lt;li&gt;In Thunderbird, go to Tools-&gt;Extensions and click on the Install button. Browse to the file you just downloaded and click on Open. &lt;br /&gt;&lt;li&gt;Restart Thunderbird... and you're done!&lt;/ul&gt;&lt;br /&gt;By the way, the extension requires Thunderbird 1.0&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Known Limitations&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The extension works on folders only. Executing the function on an account will do nothing.&lt;br /&gt;&lt;li&gt;It does not recurse into folders. If a folder contains subfolders you'll need to run it on each subfolder manually.&lt;br /&gt;&lt;li&gt;Since the extension analyzes each folder independently, messages duplicated across folders won't be detected.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Thanks to the anonymous poster for the suggestion regarding the message IDs. It turned out that the IDs can be obtained via Thunderbird APIs (they are stored in the metadata database). There's no need to parse the emails at all.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;: a new version compatible with Thunderbird 1.5 can be found &lt;a href="http://utils.ning.com/thunderbird"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110754639906330104?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110754639906330104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110754639906330104' title='142 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110754639906330104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110754639906330104'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/duplicate-message-remover-01.html' title='Duplicate Message Remover 0.1'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>142</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110735857579532257</id><published>2005-02-02T14:29:00.000-08:00</published><updated>2005-02-02T14:31:32.570-08:00</updated><title type='text'>two of each</title><content type='html'>&lt;blockquote&gt;[He] held one finger up directly in from of Yossarian and demanded, "How many fingers do you see?"&lt;br /&gt;"Two", said Yossarian.&lt;br /&gt;"How many fingers do you see now?" asked the doctor, holding up two.&lt;br /&gt;"Two", said Yossarian.&lt;br /&gt;"And how many now?" asked the doctor, holding up none.&lt;br /&gt;"Two", said Yossarian.&lt;br /&gt;The doctor's face wreathed with a smile. "By Jove, he's right," he declared jubilantly. "He &lt;em&gt;does&lt;/em&gt; see everything twice."&lt;br /&gt;&lt;/blockquote&gt;&lt;p align="right"&gt;In &lt;em&gt;Catch-22&lt;/em&gt;, by Joseph Heller.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;For some mysterious reason, Thunderbird occasionally downloads my emails twice from the POP server. I think it may be related with the fact that I use to email clients (home and office) to suck emails from the server. But I also remember seeing this happen in Outlook in a previous life. So maybe it the server's fault rather than Thunderbird's.&lt;br /&gt;&lt;br /&gt;Aaanyway, I decided to create an extension for Thunderbird that would delete duplicate emails automatically. Something that could be triggered from the context menu of a folder or account (and why not, as soon as an email arrives).&lt;br /&gt;&lt;br /&gt;So the approach goes like this. The program iterates over every email in a folder or account and computes a hash for each email, using some function such as MD5. It then stores the hash in a map, associating it with the email (or rather, a reference to the email. We don't want to store the contents of every email in memory). But, if the map already contains an entry for that hash, it means we're probably facing a duplicate email. So the program compares the contents of both emails to rule out any chance of them having the same hash by coincidence (very unlikely, but possible).&lt;br /&gt;&lt;br /&gt;So far so good. After a few cycles of writing and testing the Javascript code (writing mozilla extensions is messy, I tell you) I got to a point where it could detect duplicate emails (no deletion yet).&lt;br /&gt;&lt;br /&gt;To my surprise, when I ran it the browser locked up for a few seconds. I eventually discovered what the problem was and I'll get to it after I describe how to program is structured.&lt;br /&gt;&lt;br /&gt;There's a main function, deleteDuplicateMessages() that is invoked when the menu item is clicked on. This function iterates over the set of message headers (Thunderbird objects that contain metadata about each email) and invokes an asynchronous method to stream the contents of the email. The function takes an &lt;em&gt;callback&lt;/em&gt; object as an argument. I believe they had to implement it like that to support IMAP, where getting the contents of an email could take a while.&lt;br /&gt;&lt;br /&gt;The callback object gathers all the pieces of the email as it is streamed, strips out the headers and computes the MD5 hash. It then makes sure the entry does not exist in the hash map and exits.&lt;br /&gt;&lt;br /&gt;The reason for the lockup is two-fold. First, there's the issue with the &lt;a href="http://pajhome.org.uk/crypt/md5/"&gt;MD5 library&lt;/a&gt; I'm using, which takes a few seconds to compute the hash for really long strings.&lt;br /&gt;&lt;br /&gt;The second issue seems to be that Javascript code in Mozilla executes in the UI thread, regardless of whether it's a callback function being invoked by a native component. So what's happening here is that the computation of the MD5 hash executes in the UI thread and prevents the Thunderbird from responding to user events.&lt;br /&gt;&lt;br /&gt;I've been trying to find how to make that callback run in a separate thread, without much luck.&lt;br /&gt;&lt;br /&gt;Another alternative would be to write the callback object in C++ as an XPCOM component, but I wanted to make the extension as portable as possible. Creating a native XPCOM component would mean that I'd have to compile it for every platform I wish my extension to support. Too bad. &lt;br /&gt;&lt;br /&gt;The quest goes on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110735857579532257?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110735857579532257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110735857579532257' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110735857579532257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110735857579532257'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/two-of-each.html' title='two of each'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110737293452873637</id><published>2005-02-02T11:11:00.000-08:00</published><updated>2005-02-02T11:35:34.526-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Default initializer for Hash entries</title><content type='html'>zenspider made an interesting observation in a comment to my &lt;a href="http://split-s.blogspot.com/2005/01/conditional-initialization-in-ruby.html"&gt;conditional initialization&lt;/a&gt; post. He suggests to use the following construct instead:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def initialize&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  @map = Hash.new { |hash, key| hash[key] = [] }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def addToList(key, val)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  @map[key] &lt;&lt; val&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Yes, this is definitely more readable. This goes to show, as I mentioned in my reply to his comment, that when switching between languages we need to *think* in the new language. Performing direct "syntax translation" results the kind of code I posted earlier. The ability to think in a new language comes with practice, just like it does when switching "speakable" languages such as Spanish and English.&lt;br /&gt;&lt;br /&gt;In the code above, we're passing a block to the &lt;span style="font-family:Courier"&gt;new&lt;/span&gt; method of Hash. This block is invoked by the hash object whenever an entry that doesn't exist is requested, and the item returned is the value returned by the block (in this case, the result of evaluating hash[key] = [], that is, []).&lt;br /&gt;&lt;br /&gt;The only disadvantage here is that any time we try to get the value associated with a key, an entry is created in the hashmap. So it really depends on how the hash is going to be used in the larger context of the program.&lt;br /&gt;&lt;br /&gt;Anyway, it's a cool feature that I'm adding to my bag of tricks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110737293452873637?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110737293452873637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110737293452873637' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110737293452873637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110737293452873637'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/default-initializer-for-hash-entries.html' title='Default initializer for Hash entries'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110729540753678607</id><published>2005-02-01T13:49:00.000-08:00</published><updated>2005-02-01T16:38:02.686-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Quack, quack</title><content type='html'>&lt;em&gt;&lt;blockquote&gt;If it walks like a duck and quacks like a duck, then it must be a duck.&lt;/blockquote&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;The type systems of Java and Ruby are very different. First and foremost, Java is more statically-typed than Ruby. Then there or other features that pull them appart, such as the fact that in Ruby everything (or almost) is an object, while in Java there are some things that don't qualify as such (primitive types, functions). But there's a more more fundamental, philosophical, difference; namely, the intention behind the type systems.&lt;br /&gt;&lt;br /&gt;First of all, let me make a subtle but important distinction that will help understand what comes next. When I refer to the &lt;span style="font-style:italic;"&gt;class&lt;/span&gt; of an object, I'm talking about the class it was created from. For instance, in Java, &lt;span style="font-family:Courier"&gt;new String()&lt;/span&gt; creates an object of class String, just like &lt;span style="font-family:Courier"&gt;String.new&lt;/span&gt; does in Ruby. The &lt;span style="font-style:italic;"&gt;type&lt;/span&gt; of an object is the set of roles the object can play. Thus, the type of a class is not the same as the class, but typically includes it.&lt;br /&gt;&lt;br /&gt;Java uses inheritance (loosely speaking) as the mechanism for defining the type of an object. An object &lt;span style="font-style:italic;"&gt;"is a" X&lt;/span&gt; if it implements X. While Ruby also supports inheritance, establishing "is a" relationships is not its main purpose. In Ruby an object is of a certain type if it &lt;em&gt;behaves&lt;/em&gt; as that type. Thus the saying "if it walks like a duck and quacks like a duck, then it must be a duck" or as it is commonly called, &lt;em&gt;Duck typing&lt;/em&gt;. It must be noted, however, that while Ruby has classes, objects are not explicitly declared of to have a certain type.&lt;br /&gt;&lt;br /&gt;So, what, concretely, defines what type an object is in Ruby? Well, that's the wrong question to ask. But if you'd still like to hear an answer, an object, conceptually, is of N! types (made of the subsets of all the combinations of methods exposed by the object), where N is the number of methods exposed by the the object, &lt;br /&gt;&lt;br /&gt;In a sense, Ruby shifts the notion of type to the &lt;em&gt;client&lt;/em&gt; (the client being the code that uses a given object). Thus, an object is (or not) of the type required by client if it implements the operations required by the client.&lt;br /&gt;&lt;br /&gt;Ruby types are more granular as well, with the method being the atomic component of the type. In contrast, Java types are defined class by class, interface by interface. &lt;br /&gt;&lt;br /&gt;Of course, this is all possible because Ruby is dynamically typed. That, together with the executable definitions concept I &lt;a href="http://split-s.blogspot.com/2005/02/definition-time-execution-time-anytime.html"&gt;posted about before&lt;/a&gt; also allows type to vary by object. In Java, all objects created from the same class have the same type, and that type includes the class. In Ruby that may not be so. Look at this piece of code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class SomeClass&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def method&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;puts "within method"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;value = SomeClass.new&lt;br /&gt;value.method    # prints out "within method"&lt;br /&gt;&lt;br /&gt;class &lt;&lt; value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private :method&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;value.method    # fails with "NoMethodError: private method `method' called for ...&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/9469017-110729540753678607?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110729540753678607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110729540753678607' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110729540753678607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110729540753678607'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/quack-quack.html' title='Quack, quack'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110729233652417335</id><published>2005-02-01T12:37:00.000-08:00</published><updated>2005-12-22T16:57:49.563-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Definition-time, execution-time, anytime!</title><content type='html'>From "Programming Ruby", by David Thomas and Andrew Hunt:&lt;br /&gt;&lt;div style="font-style:italic"&gt;&lt;blockquote&gt;The important thing to remember about Ruby is that there isn't a big difference between “compile time” and “runtime.” It's all the same. You can add code to a running process. You can redefine methods on the fly, change their scope from public to private, and so on. You can even alter basic types, such as Class and Object.&lt;/blockquote&gt;&lt;/div&gt;&lt;br /&gt;To this, I would like to add that Ruby blurs the distinction between &lt;em&gt;definition-time&lt;/em&gt; and runtime. While definition-time may resemble, and frequently overlap, compile-time, there's a subtle difference.&lt;br /&gt;&lt;br /&gt;In Java and other compiled languages, it is the compiler who interprets the class definition and produces an internal representation that the runtime portions will use. In contrast, in Ruby, it is the interpreter the one who does this. But more importantly, the class and method definitions are &lt;em&gt;executed&lt;/em&gt;. As opposed to being parsed to extract the definitions before the code starts to execute.&lt;br /&gt;&lt;br /&gt;In that sense, a class and method definition is part of the executable code, and the line between definition and actual code begins to fade. &lt;br /&gt;&lt;br /&gt;It is this simple concept that enables Ruby to programs to create classes, add methods and attributes to classes and objects at runtime.&lt;br /&gt;&lt;br /&gt;To illustrate these points, consider this piece of code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;c = &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    class SomeClass&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        attr :value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        self&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Before analyzing the code, remember that in Ruby every statement returns a value. In the case of a class definition, the value returned is the result of the last evaluated line.&lt;br /&gt;&lt;br /&gt;When the Ruby interpreter sees this above code, it defines a class named &lt;span style="font-family:Courier"&gt;SomeClass&lt;/span&gt;, creates an getter and setter for an attribute named &lt;span style="font-family:Courier"&gt;value&lt;/span&gt; and assigns the result of evaluating &lt;span style="font-family:Courier"&gt;self&lt;/span&gt;(i.e., a reference to SomeClass itself) to &lt;span style="font-family:Courier"&gt;c&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;And then we can also do the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;obj = c.new&lt;br /&gt;def obj.aMethod&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   puts "Custom-made method"&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This example reinforces the notion that definitions are executable code, and can intermingled arbitrarily with &lt;em&gt;regular code&lt;/em&gt;(emphasized because in Ruby there's no such thing as regular code). &lt;br /&gt;&lt;br /&gt;&lt;em&gt;Executable definitions&lt;/em&gt; is a simple, but powerful concept. I'm still trying to understand all its implications and possibilities it opens.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110729233652417335?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110729233652417335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110729233652417335' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110729233652417335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110729233652417335'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/definition-time-execution-time-anytime.html' title='Definition-time, execution-time, anytime!'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110728418208598240</id><published>2005-02-01T11:23:00.000-08:00</published><updated>2005-02-01T13:23:14.046-08:00</updated><title type='text'>Strong/Weak vs Static/Dynamic typing</title><content type='html'>During the past week, while imbuing myself with Ruby knowledge, I came across a few discussions about the nature of Ruby vs that of other languages such as Java, Python, Perl, etc. Most of those discussions centered around the type systems in each language. &lt;br /&gt;&lt;br /&gt;It seems quite common for people to mix the concepts of strong/weak and static/dynamic language typing. Let me clarify, these are two different categories, almost orthogonal to each other. A language can be strongly-typed and dynamically-typed at the same time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Static vs Dynamic&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Informally, a statically typed language enforces type consistency at compilation time, whereas a dynamically typed language defers this until runtime. In reality, there's a wide gamut of "typing dynamism" so it would be incorrect to say that every language falls into either category. At one end of the spectrum lie languages such as ML or Haskell; at the other end, languages like Lisp. Java and C++ lie close to the statically-typed end, whereas Ruby and Python lie close to the opposite end.&lt;br /&gt;&lt;br /&gt;Here's an example of dynamic typing, in Ruby:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class Car&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		attr :price&lt;br /&gt;	end&lt;br /&gt;&lt;br /&gt;	class Apple&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		attr :price&lt;br /&gt;	end&lt;br /&gt;           &lt;br /&gt;	def calculateTotalPrice(item, quantity)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		item.price * quantity&lt;br /&gt;	end&lt;br /&gt;&lt;br /&gt;        car = Car.new&lt;br /&gt;        car.price = 300&lt;br /&gt;        calculateTotalPrice(car, 2)&lt;br /&gt;&lt;br /&gt;        apple = Apple.new&lt;br /&gt;        apple.price = 2&lt;br /&gt;        calculateTotalPrice(apple, 12)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The type of the arguments to &lt;span style="font-family:Courier;"&gt;calculateTotalPrice&lt;/span&gt; are not bound or even checked at compile type. That determination is left till the moment the method is actually called.&lt;br /&gt;&lt;br /&gt;With a statically typed language, on the other hand, the type of the actual parameters must match those of the formal parameters in a call. The example above could be rewritten in Java as:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class Item {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		float price;&lt;br /&gt;	}&lt;br /&gt;&lt;br /&gt;	class Car extends Item { }&lt;br /&gt;&lt;br /&gt;	class Apple extends Item { }&lt;br /&gt;&lt;br /&gt;	class Calculator {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		float calculateTotal(Item item, int quantity)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;			return item.price * quantity;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		}&lt;br /&gt;	}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The difference here is the introduction of the Item superclass and typed arguments for &lt;span style="font-family:Courier"&gt;calculateTotalPrice&lt;/span&gt;. Trying to call that function with anything that is not an Item will fail at compile time. Disclaimer: this is not a good way to use inheritance, since it involves bringing two unrelated classes under the same hierarchy just for interface compliance. It's just an example to illustrate static typing without excesive boilerplate.&lt;br /&gt;&lt;br /&gt;Here's a simpler example. In Ruby it we can do:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class Car; end&lt;br /&gt;class Apple; end&lt;br /&gt;&lt;br /&gt;obj = Car.new&lt;br /&gt;obj = Apple.new&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The type of &lt;span style="font-family:Courier"&gt;obj&lt;/span&gt; is determined at runtime, based on what object it points to. &lt;br /&gt;&lt;br /&gt;The Java equivalent would be:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class Car {}&lt;br /&gt;class Apple {}&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Car car = new Car()&lt;br /&gt;Apple apple = new Apple()&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier"&gt;car&lt;/span&gt; and &lt;span style="font-family:Courier"&gt;apple&lt;/span&gt; are variables of type &lt;span style="font-family:Courier"&gt;Car&lt;/span&gt; and &lt;span style="font-family:Courier"&gt;Apple&lt;/span&gt;, respectively. Attempting to assign &lt;span style="font-family:Courier"&gt;new Car&lt;/span&gt; to &lt;span style="font-family:Courier"&gt;apple&lt;/span&gt; would fail at compile-time.&lt;br /&gt;&lt;br /&gt;Of course one could replace the type of all variables with Object, effectively turning the language into a dynamically-typed one. That's one of the reasons why Java is not at the end of the spectrum, but close to it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Strong vs Weak&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is a little harder to define what a strongly vs weakly typed language is, but it revolves around the notion of how much effort does the language put into checking type consistency (either at runtime or compile time). In this sense, Java and Ruby are both strongly typed, whereas Javascript is weakly typed.&lt;br /&gt;&lt;br /&gt;In Ruby, it is possible to access only to methods and attributes that have been defined in a class or added to an object at runtime:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def ColoredObject&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    attr :color&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;obj = ColoredObject.new&lt;br /&gt;obj.color = "blue"&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Attempting to access a method or attribute not defined explicitly for the class or object will cause a runtime error.&lt;br /&gt;&lt;br /&gt;On the other hand, in weakly typed languages such errors will go unnoticed. For example, in JavaScript it is possible to access an attribute that doesn't exist in an object (it will be created on the fly):&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;var obj = new Object();&lt;br /&gt;obj.color = "blue";&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Some may say this is a feature. But it has its dangers (a simple typo can be very hard to detect and find). &lt;br /&gt;&lt;br /&gt;Ruby seems to capture the best of both worlds. While being a strongly typed language, it has a mechanism for adding methods and attributes to objects at runtime (whether even compile time exists in Ruby is the topic of another discussion :) ):&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;class Car&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;car = Car.new&lt;br /&gt;car.color = "blue" # fails with "NoMethodError: undefined method `color=' for #&lt;Car:0x402bea84&gt;"&lt;br /&gt;&lt;br /&gt;# let's add an attribute named "color"&lt;br /&gt;def car.color= (value)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   @color = value&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;car.color = "blue" # succeeds&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110728418208598240?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110728418208598240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110728418208598240' title='46 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110728418208598240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110728418208598240'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/02/strongweak-vs-staticdynamic-typing.html' title='Strong/Weak vs Static/Dynamic typing'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>46</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110706538066487756</id><published>2005-01-29T23:09:00.000-08:00</published><updated>2005-01-29T22:33:48.426-08:00</updated><title type='text'>Breaking the code</title><content type='html'>As a follow-up to my &lt;a href="http://split-s.blogspot.com/2005/01/solution-to-ghcq-challenge.html"&gt;previous post&lt;/a&gt;, I'd like to describe how the I broke the GCHQ code. All it took was a bit of luck, some detective work and some programming.&lt;br /&gt;&lt;br /&gt;The first time I saw the challenge, I skimped over the names to get a feel for it, without any intention of actually trying to solve it. It was pretty obvious to me, though, that the names had been encrypted with some kind of substitution cypher.&lt;br /&gt;&lt;br /&gt;And then I saw the tip-off... BZGZD A'GAANZ. That &lt;i&gt;had&lt;/i&gt; to be an irish-like name, so the A would be and encrypted O. Consequently, the last name would have to have the form O'xOOxx. Peter O'Toole immediately came to mind, although I didn't initially remember who he was. But the name sounded &lt;i&gt;so&lt;/i&gt; familiar. I googled for it and it turned out he was an actor. Then I remembered :), and I was hooked.&lt;br /&gt;&lt;br /&gt;I looked at the other names carefully, trying to spot easy ones, like KHP FNWHQBEV. With three distinct letters in the first name, I couldn't think of anything else than "Kim". Kim Basinger came to mind, and it fit nicely.&lt;br /&gt;&lt;br /&gt;It was then that I decided to write a program to automate the discovery. I needed the program to take a name as input and match it to each name in the list. The question was how to do this efficiently. I realized that when dealing with substitution cyphers, an unencrypted string has the same &lt;i&gt;form&lt;/i&gt; as the encrypted version. For example, PETER could be described as a sequence of characters [a, b, c, d, e] where a = P, b = d = E, c = T, e = R. It can be rewritten as [a, b, c, b, e], or "abcbe". In a sense, this sequence is a &lt;i&gt;canonical form&lt;/i&gt; for the string. This (Ruby) code snippet will do the transformation:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def canonicalForm(chars)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    map = {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    	currentIndex = 64&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    	result = ""&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    	chars.each_byte { |char|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        		if not Regexp.new("[' ]") =~ char.chr&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;            			index = map[char] ||= (currentIndex += 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        		else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;            			index = char&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        		end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        		result &amp;lt;&amp;lt; index&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;		    	}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    	return result&lt;br /&gt;end&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;A string and its encrypted version will both have the same canonical form. For instance, for PETER O'TOOLE and BZGZD A'GAANZ, the canonical form is ABCBD E'CEEFB.&lt;br /&gt;&lt;br /&gt;The original version was quite primitive... if you fed it a name it would tell you which, if any, encrypted names matched. I discovered a few names with this approach. At first I thought the actors and actresses were Oscar winners, but I quickly dropped that hypothesis when I encountered "Kirsten Dunst". Given that she performed in Spiderman, I decided to try "Tobey Maguire". Direct hit! So my new theory was that an actor and actress that had performed in the same movie would be paired together. But I had to test it.&lt;br /&gt;&lt;br /&gt;That's when I came up with the second version of the program, one that would build the cypher given a string and its encrypted version. For example, if I provided it with TOBEY MAGUIRE and DYFJN WCLEQPJ, it would produce &lt;br /&gt;&lt;br /&gt;&lt;center&gt;CF..J.L.Q...W.Y..P.DE...N.&lt;/center&gt;&lt;br /&gt;The dots represent unknown substitutions. If I did the same with Kirsten Dunst, I'd get &lt;br /&gt;&lt;br /&gt;&lt;center&gt;...HJ...Q.U..X...PIDE.....&lt;/center&gt;&lt;br /&gt;If you take a close look at the cyphers, you'll notice that they look awfully similar (the J, Q, P, D, and E are in the same positions). If you merge them, you get&lt;br /&gt;&lt;br /&gt;&lt;center&gt;CF.HJ.L.Q.U.WXY..PIDE...N.&lt;/center&gt;&lt;br /&gt;Also, you'll note that the merged cypher is very regular and that the letters seem to be, up to a point, in alphabetical order. We can confidently fill in some of the missing spaces, for only one letter seems to fit: &lt;br /&gt;&lt;br /&gt;&lt;center&gt;CF&lt;span style="color:#ff0000;"&gt;G&lt;/span&gt;HJ&lt;span style="color:#ff0000;"&gt;K&lt;/span&gt;L.Q.U&lt;span style="color:#ff0000;"&gt;V&lt;/span&gt;WXY..PIDE...N.&lt;/center&gt;&lt;br /&gt;The last portion is suspiciously close to Spiderman, the name of the movie. That was one of the tell-tale signs that confirmed that the cyphers were unique to each pair, and that they were built from the name of the movie. Completing the cypher with the missing letters from Spiderman we get &lt;br /&gt;&lt;br /&gt;&lt;center&gt;CFGHJKL.Q.UVWXY.&lt;span style="color:#ff0000;"&gt;S&lt;/span&gt;PIDE&lt;span style="color:#ff0000;"&gt;RMA&lt;/span&gt;N.&lt;/center&gt;&lt;br /&gt;That leaves only a few letters left, which, again, we can detemine unequivocally:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;CFGHJKL&lt;span style="color:#ff0000;"&gt;O&lt;/span&gt;Q&lt;span style="color:#ff0000;"&gt;T&lt;/span&gt;UVWXY&lt;span style="color:#ff0000;"&gt;Z&lt;/span&gt;SPIDERMAN&lt;span style="color:#ff0000;"&gt;B&lt;/span&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Some names were still missing their pair. I was able to infer a few by applying the cyphers of the still-unpaired names to the remaining encrypted names. For example, the cypher for Sean Connery produced &lt;em&gt;.ONOR...AC..AN&lt;/em&gt; when decrypting one of the names. &lt;em&gt;.ONOR&lt;/em&gt; could be nothing else than "Honor", so I queried &lt;a href="http://www.imdb.com/"&gt;www.imdb.com&lt;/a&gt; for all the people named that way. The first entry in the list was "Honor Blackman". Another direct hit!&lt;br /&gt;&lt;br /&gt;At this point I was out of luck. I had no idea how to decrypt the remaining names and I had tried with all the actors and actresses I could remember. That's when I decided to investigate if IMDb had a programmatic interface. It did not, but it was possible to download the list of all known actors and actresses in a text file. Oh yeah, baby!&lt;br /&gt;&lt;br /&gt;The third incarnation of the program would parse the text files and attempt to decrypt each of the remaining names with each of the names in the file. Surprisingly, some names produced unambiguous translations, but others resulted in dozens of alternatives. And I was &lt;i&gt;not&lt;/i&gt; going to try one by one.&lt;br /&gt;&lt;br /&gt;During the few minutes I spent thinking about how to best tackle the problem ahead I contemplated a couple of alternatives and I made an interesting discovery: if I picked any name (with Ae and Ad being the encrypted and decrypted versions, respectively) and another name B (with Be and Bd following the same rule as A), such that A and B are encrypted with the same cypher, the concatenation of Ae with Be has the same canonical form as the concatenation of Ad with Bd. If you stop to think about it for a second it, it makes perfect sense. Just consider what happens &lt;i&gt;within&lt;/i&gt; a name. The encrypted and decrypted versions of the first name have the same canonical form. If we add the last name, which is written in terms of the &lt;i&gt;standard&lt;/i&gt; alphabet in the decrypted version, and in a non-standard alphabet resulting applying the cypher on the standard alphabet, the strings are still isomorphic (i.e., they have the same canonical form). Thus, it follows that if we add a full name to each of the strings, each in their respective alphabet, the result will still be two isomorphic strings.&lt;br /&gt;&lt;br /&gt;In the fourth incarnation, the program would pair up all the alternatives for the names that I hadn't been able to decrypt and make sure that their concatenation was isomorphic with the contatenation of the encrypted versions. Amazingly, the program produce one and only one pairing for each name! I was done with the first step.&lt;br /&gt;&lt;br /&gt;Next, I had to figure out what were the names of the movies, since I had a hunch that the hidden quotation would be buried somewhere within the cyphers. I could've written a program to extract this information from the IMDb text files, but they are not well structured and I considered that it would take me longer to figure out how to parse them than to query IMDd. It did take some going back and forth in IMDb, but it wasn't that bad. Plus, I had already figured out most of the names, anyway.&lt;br /&gt;&lt;br /&gt;Finding the hidden quotation took me a while, though. I tried everything I could possibly think of, to no avail. Then, it simply clicked. I looked at the release dates of the movies and noticed they were all different, and ranged from the 40's up to the present day. That could imply only one thing: they were meant to be sorted! And so I did. I sorted the cyphers based on the release date, in ascending order. And it didn't take me long to realize that the quote was in the diagonal of the matrix formed by the cyphers.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110706538066487756?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110706538066487756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110706538066487756' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110706538066487756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110706538066487756'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/breaking-code.html' title='Breaking the code'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110703194632321793</id><published>2005-01-29T12:36:00.000-08:00</published><updated>2005-01-29T12:53:45.850-08:00</updated><title type='text'>no that protected, it seems</title><content type='html'>During a conversation with &lt;a href="http://www.dynamicobjects.com/d2r"&gt;Diego&lt;/a&gt; today, he pointed out that the &lt;em&gt;protected&lt;/em&gt; qualifier in Java does not prevent access to classes within the same package.&lt;br /&gt;&lt;br /&gt;That was news to me. I always thought protected limited the access to subclasses of the class that contains the protected member.&lt;br /&gt;&lt;br /&gt;As Diego &lt;a href="http://www.dynamicobjects.com/d2r/archives/003090.html"&gt;points out&lt;/a&gt; in his weblog, it seems the Java Language Specification is incomplete. The ambiguity is actually cleared up in &lt;a href="http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#102765"&gt;section 6.6.1&lt;/a&gt; of the spec:&lt;br /&gt;&lt;em&gt;&lt;ul&gt;    &lt;li&gt;A member (class, interface, field, or method) of a reference (class, interface, or array) type or a constructor of a class type is accessible only if the type is accessible and the member or constructor is declared to permit access:&lt;br /&gt;&lt;ul&gt;          &lt;li&gt;If the member or constructor is declared public, then access is permitted. All members of interfaces are implicitly public.          &lt;li&gt;Otherwise, if the member or constructor is declared protected, then access is permitted only when one of the following is true:&lt;ul&gt;                       &lt;li&gt;&lt;b&gt;Access to the member or constructor occurs from within the package containing the class in which the protected member or constructor is declared.&lt;/b&gt;                      &lt;li&gt;&lt;b&gt; Access is correct as described in §6.6.2. &lt;/b&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110703194632321793?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110703194632321793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110703194632321793' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110703194632321793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110703194632321793'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/no-that-protected-it-seems.html' title='no &lt;em&gt;that&lt;/em&gt; protected, it seems'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110701934995343271</id><published>2005-01-29T09:03:00.000-08:00</published><updated>2005-01-29T09:22:29.953-08:00</updated><title type='text'>Amazon Gold Box ... gone</title><content type='html'>I just realized that Amazon has yanked the Gold Box feature from their site. &lt;br /&gt;&lt;br /&gt;In the past two or so years I occasionally opened the gold box in search of a good deal. And never was I offered anything I may have remotely wished for. Items such as power tools, kitchen appliances and jewelry were common. &lt;br /&gt;&lt;br /&gt;One would think the gold box would offer deals for items that were in one's wish list or related to stuff bought in in the past. Quite the opposite, items I had never even &lt;em&gt;browsed&lt;/em&gt; for showed up.&lt;br /&gt;&lt;br /&gt;I say, good riddance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110701934995343271?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110701934995343271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110701934995343271' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110701934995343271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110701934995343271'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/amazon-gold-box-gone.html' title='Amazon Gold Box ... gone'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110689094665990151</id><published>2005-01-27T21:09:00.000-08:00</published><updated>2006-08-13T19:12:27.120-07:00</updated><title type='text'>Solution to the GCHQ challenge</title><content type='html'>As &lt;a href="http://split-s.blogspot.com/2005/01/gchq-challenge.html"&gt;promised&lt;/a&gt;, here's the solution to the challenge.&lt;br /&gt;&lt;br /&gt;The names in the two lists are those of actors and actresses. They are encoded using a simple substitution cypher. There's one cypher for each pair of men and women, built from the name of the movie they performed in together. These are the translations:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="2" align="left"&gt;&lt;b&gt;Men&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;QJAMDU WWVDU&lt;/td&gt;&lt;td&gt;MICKEY ROONEY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KCRVKXHL EUJDXZ&lt;/td&gt;&lt;td&gt;HUMPHREY BOGART&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;XCT GSXXJYUQ&lt;/td&gt;&lt;td&gt;REX HARRISON&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;JRFJWRI XFCS&lt;/td&gt;&lt;td&gt;GREGORY PECK&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NRIKUSL UIQORMDB&lt;/td&gt;&lt;td&gt;CHARLES LAUGHTON&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;QFDX ORNQTP&lt;/td&gt;&lt;td&gt;TONY CURTIS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UFIV WKXXZY&lt;/td&gt;&lt;td&gt;JACK LEMMON&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;HYUE WREEYCS&lt;/td&gt;&lt;td&gt;SEAN CONNERY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WKNJVWL GSWOXU&lt;/td&gt;&lt;td&gt;RICHARD BURTON&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BZGZD A'GAANZ&lt;/td&gt;&lt;td&gt;PETER O'TOOLE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VTWMAC UEIIML&lt;/td&gt;&lt;td&gt;ALBERT FINNEY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ZGRT BPDIIRNN&lt;/td&gt;&lt;td&gt;ALEC GUINNESS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;XIVL VFBD&lt;/td&gt;&lt;td&gt;JOHN HURT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GMTHYL IKUBGMFPTPSSPM&lt;/td&gt;&lt;td&gt;ARNOLD SCHWARZENEGGER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OFIIPTYX LYIJ&lt;/td&gt;&lt;td&gt;HARRISON FORD&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RNBTCNP TCOSHNM&lt;/td&gt;&lt;td&gt;ANTHONY HOPKINS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KEZHQ WSNIEC&lt;/td&gt;&lt;td&gt;KEVIN SPACEY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LVZD CONKLNFK&lt;/td&gt;&lt;td&gt;EWAN MCGREGOR&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DYFJN WCLEQPJ&lt;/td&gt;&lt;td&gt;TOBEY MAGUIRE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PZSS TEBBMJ&lt;/td&gt;&lt;td&gt;BILL MURRAY&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="2" align="left"&gt;&lt;b&gt;Women&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LRNU FHZOHVN&lt;/td&gt;&lt;td&gt;JUDY GARLAND&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MTJXMG EHXJRDT&lt;/td&gt;&lt;td&gt;INGRID BERGMAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OSXFSXCZ XBZGCXDUXA&lt;/td&gt;&lt;td&gt;MARGARET RUTHERFORD&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;YAERFI KFXBARV&lt;/td&gt;&lt;td&gt;AUDREY HEPBURN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AIKUSBS EHSMKHNR&lt;/td&gt;&lt;td&gt;MARLENE DIETRICH&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CZNTBXD CFDNFE&lt;/td&gt;&lt;td&gt;MARILYN MONROE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AQSEWKC XFIWFSYK&lt;/td&gt;&lt;td&gt;SHIRLEY MACLAINE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ORERC VIUWFNUE&lt;/td&gt;&lt;td&gt;HONOR BLACKMAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BQKDVGBOJ OVIQXW&lt;/td&gt;&lt;td&gt;ELIZABETH TAYLOR&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OUGEUDLRZ EZBVJDR&lt;/td&gt;&lt;td&gt;KATHARINE HEPBURN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TVFAMI WVYVTT&lt;/td&gt;&lt;td&gt;LAUREN BACALL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TZMMDR WDNCRM&lt;/td&gt;&lt;td&gt;CARRIE FISHER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CWUIFBLSK HSOGSB&lt;/td&gt;&lt;td&gt;SIGOURNEY WEAVER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;YVTLG UGZVYNHT&lt;/td&gt;&lt;td&gt;LINDA HAMILTON&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RKUUC VHMPUUPT&lt;/td&gt;&lt;td&gt;KELLY MCGILLIS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ECWHX YCMBXA&lt;/td&gt;&lt;td&gt;JODIE FOSTER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KHP FNWHQBEV&lt;/td&gt;&lt;td&gt;KIM BASINGER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DGOFBL AGUCZD&lt;/td&gt;&lt;td&gt;NICOLE KIDMAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UQPIDJX HEXID&lt;/td&gt;&lt;td&gt;KIRSTEN DUNST&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CQMBSVDD LNYMICCNI&lt;/td&gt;&lt;td&gt;SCARLETT JOHANSSON&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;And here's how they relate to each other and the name of each movie:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;STRIKE UP THE BAND&lt;/td&gt;&lt;td&gt;MICKEY ROONEY&lt;/td&gt;&lt;td&gt;JUDY GARLAND&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CASABLANCA&lt;/td&gt;&lt;td&gt;HUMPHREY BOGART&lt;/td&gt;&lt;td&gt;INGRID BERGMAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BLITHE SPIRIT&lt;/td&gt;&lt;td&gt;REX HARRISON&lt;/td&gt;&lt;td&gt;MARGARET RUTHERFORD&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ROMAN HOLIDAY&lt;/td&gt;&lt;td&gt;GREGORY PECK&lt;/td&gt;&lt;td&gt;AUDREY HEPBURN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WITNESS FOR THE PROSECUTION&lt;/td&gt;&lt;td&gt;CHARLES LAUGHTON&lt;/td&gt;&lt;td&gt;MARLENE DIETRICH&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SOME LIKE IT HOT&lt;/td&gt;&lt;td&gt;TONY CURTIS&lt;/td&gt;&lt;td&gt;MARILYN MONROE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;THE APARTMENT&lt;/td&gt;&lt;td&gt;JACK LEMMON&lt;/td&gt;&lt;td&gt;SHIRLEY MACLAINE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GOLDFINGER&lt;/td&gt;&lt;td&gt;SEAN CONNERY&lt;/td&gt;&lt;td&gt;HONOR BLACKMAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WHO'S AFRAID OF VIRGINIA WOOLF&lt;/td&gt;&lt;td&gt;RICHARD BURTON&lt;/td&gt;&lt;td&gt;ELIZABETH TAYLOR&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;THE LION IN WINTER&lt;/td&gt;&lt;td&gt;PETER O'TOOLE&lt;/td&gt;&lt;td&gt;KATHARINE HEPBURN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MURDER ON THE ORIENT EXPRESS&lt;/td&gt;&lt;td&gt;ALBERT FINNEY&lt;/td&gt;&lt;td&gt;LAUREN BACALL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;STAR WARS&lt;/td&gt;&lt;td&gt;ALEC GUINNESS&lt;/td&gt;&lt;td&gt;CARRIE FISHER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ALIEN&lt;/td&gt;&lt;td&gt;JOHN HURT&lt;/td&gt;&lt;td&gt;SIGOURNEY WEAVER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;THE TERMINATOR&lt;/td&gt;&lt;td&gt;ARNOLD SCHWARZENEGGER&lt;/td&gt;&lt;td&gt;LINDA HAMILTON&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WITNESS&lt;/td&gt;&lt;td&gt;HARRISON FORD&lt;/td&gt;&lt;td&gt;KELLY MCGILLIS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;THE SILENCE OF THE LAMBS&lt;/td&gt;&lt;td&gt;ANTHONY HOPKINS&lt;/td&gt;&lt;td&gt;JODIE FOSTER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LA CONFIDENTIAL&lt;/td&gt;&lt;td&gt;KEVIN SPACEY&lt;/td&gt;&lt;td&gt;KIM BASINGER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MOULIN ROUGE&lt;/td&gt;&lt;td&gt;EWAN MCGREGOR&lt;/td&gt;&lt;td&gt;NICOLE KIDMAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SPIDERMAN&lt;/td&gt;&lt;td&gt;TOBEY MAGUIRE&lt;/td&gt;&lt;td&gt;KIRSTEN DUNST&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LOST IN TRANSLATION&lt;/td&gt;&lt;td&gt;BILL MURRAY&lt;/td&gt;&lt;td&gt;SCARLETT JOHANSSON&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The cyphers are created by taking the name of the movie, capitalizing it, removing duplicate letters and completing the string with the missing letters from the alphabet, in alphabetical order. The string is then shift-rotated by a certain number of positions.&lt;br /&gt;&lt;br /&gt;For example, if the movie is "The silence of the lambs", we get "THESILNCOFAMB" after the first two steps. We then add the missing letters and obtain "THESILNCOFAMBDGJKPQRUVWXYZ". The cypher is then shift-rotated to produce "RUVWXYZTHESILNCOFAMBDGJKPQ".&lt;br /&gt;&lt;br /&gt;You may be wondering how is that used to encrypt the actor name. Simple, replace each letter in the name with the letter that appears in the cypher in the position that corresponds to the original letter's position in the alphabet. For instance, to encrypt an F we look at the 6th position in the cypher (F is the 6th letter of the alphabet) and find a Y.&lt;br /&gt;&lt;br /&gt;To find the hidden quotation we first listing all cyphers to form a matrix (26x20). They should be sorted according to the movie release date, in ascending order. The hidden quotation can be read from the diagonal of the matrix, starting top-left corner and going down and to the right. The phrase reads "Here's looking at you, kid", a quote from Casablanca.&lt;br /&gt;&lt;br /&gt;&lt;font face="courier"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;font color="#FF0000"&gt;H&lt;/font&gt;BANDCFGJLMOQVWXYZSTRIKEUP&lt;/td&gt;&lt;td&gt;&amp;nbsp;STRIKE UP THE BAND&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;D&lt;font color="#FF0000"&gt;E&lt;/font&gt;FGHIJKMOPQRTUVWXYZCASBLN&lt;/td&gt;&lt;td&gt;&amp;nbsp;CASABLANCA&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SP&lt;font color="#FF0000"&gt;R&lt;/font&gt;ACDFGJKMNOQUVWXYZBLITHE&lt;/td&gt;&lt;td&gt;&amp;nbsp;BLITHE SPIRIT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;YBC&lt;font color="#FF0000"&gt;E&lt;/font&gt;FGJKPQSTUVWXZROMANHLID&lt;/td&gt;&lt;td&gt;&amp;nbsp;ROMAN HOLIDAY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ITNE&lt;font color="#FF0000"&gt;S&lt;/font&gt;FORHPCUABDGJKLMQVXYZW&lt;/td&gt;&lt;td&gt;&amp;nbsp;WITNESS FOR THE PROSECUTION&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ZSOME&lt;font color="#FF0000"&gt;L&lt;/font&gt;IKTHABCDFGJNPQRUVWXY&lt;/td&gt;&lt;td&gt;&amp;nbsp;SOME LIKE IT HOT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FGIJKL&lt;font color="#FF0000"&gt;O&lt;/font&gt;QSUVWXYZTHEAPRMNBCD&lt;/td&gt;&lt;td&gt;&amp;nbsp;THE APARTMENT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UVWXYZG&lt;font color="#FF0000"&gt;O&lt;/font&gt;LDFINERABCHJKMPQST&lt;/td&gt;&lt;td&gt;&amp;nbsp;GOLDFINGER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VGNLBCEJ&lt;font color="#FF0000"&gt;K&lt;/font&gt;MPQTUXYZWHOSAFRID&lt;/td&gt;&lt;td&gt;&amp;nbsp;WHO'S AFRAID OF VIRGINIA WOOLF&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UVXYZTHEL&lt;font color="#FF0000"&gt;I&lt;/font&gt;ONWRABCDFGJKMPQS&lt;/td&gt;&lt;td&gt;&amp;nbsp;THE LION IN WINTER&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VWYZMURDEO&lt;font color="#FF0000"&gt;N&lt;/font&gt;THIXPSABCFGJKLQ&lt;/td&gt;&lt;td&gt;&amp;nbsp;MURDER ON THE ORIENT EXPRESS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ZSTARWBCDEF&lt;font color="#FF0000"&gt;G&lt;/font&gt;HIJKLMNOPQUVXY&lt;/td&gt;&lt;td&gt;&amp;nbsp;STAR WARS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OPQRSTUVWXYZ&lt;font color="#FF0000"&gt;A&lt;/font&gt;LIENBCDFGHJKM&lt;/td&gt;&lt;td&gt;&amp;nbsp;ALIEN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GJKLPQSUVWXYZ&lt;font color="#FF0000"&gt;T&lt;/font&gt;HERMINAOBCDF&lt;/td&gt;&lt;td&gt;&amp;nbsp;THE TERMINATOR&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FGHJKLMOPQRUVX&lt;font color="#FF0000"&gt;Y&lt;/font&gt;ZWITNESABCD&lt;/td&gt;&lt;td&gt;&amp;nbsp;WITNESS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RUVWXYZTHESILNC&lt;font color="#FF0000"&gt;O&lt;/font&gt;FAMBDGJKPQ&lt;/td&gt;&lt;td&gt;&amp;nbsp;THE SILENCE OF THE LAMBS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NFIDETBGHJKMPQRS&lt;font color="#FF0000"&gt;U&lt;/font&gt;VWXYZLACO&lt;/td&gt;&lt;td&gt;&amp;nbsp;LA CONFIDENTIAL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ZMOULINRGEABCDFHJ&lt;font color="#FF0000"&gt;K&lt;/font&gt;PQSTVWXY&lt;/td&gt;&lt;td&gt;&amp;nbsp;MOULIN ROUGE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CFGHJKLOQTUVWXYZSP&lt;font color="#FF0000"&gt;I&lt;/font&gt;DERMANB&lt;/td&gt;&lt;td&gt;&amp;nbsp;SPIDERMAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MPQUVWXYZLOSTINRABC&lt;font color="#FF0000"&gt;D&lt;/font&gt;EFGHJK&lt;/td&gt;&lt;td&gt;&amp;nbsp;LOST IN TRANSLATION&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Here's a Ruby &lt;a href="http://clans.gameclubcentral.com/shoot/weblog/challenge.rb"&gt;script&lt;/a&gt; to automate the decryption process. You'll also need to get the list of &lt;a href="http://clans.gameclubcentral.com/shoot/weblog/movies.txt"&gt;movies&lt;/a&gt; and the actors.list and actresses.list files from IMDB's text &lt;a href="ftp://ftp.fu-berlin.de/pub/misc/movies/database/"&gt;database&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110689094665990151?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110689094665990151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110689094665990151' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110689094665990151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110689094665990151'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/solution-to-gchq-challenge.html' title='Solution to the GCHQ challenge'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110678017256880222</id><published>2005-01-26T14:49:00.000-08:00</published><updated>2005-01-26T21:45:10.983-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Conditional initialization in Ruby </title><content type='html'>Exploring Ruby further, I came accross the || operator. It behaves like the boolean &lt;span style="font-style:italic;"&gt;or&lt;/span&gt; operator in other languages (Java, C++) but with a catch: it returns the value of the last evaluated term. Since evaluation is lazy (from left to right), the last evaluated term is either the first &lt;span style="font-style:italic;"&gt;non-false&lt;/span&gt; (I'll qualify this later on, bear with me) term or the last term in the expression. &lt;br /&gt;&lt;br /&gt;More concretely, the expression &lt;span style="font-style:italic;"&gt;d = a || b || c&lt;/span&gt; will assign the value of &lt;span style="font-style:italic;"&gt;a&lt;/span&gt; to &lt;span style="font-style:italic;"&gt;d&lt;/span&gt; if &lt;span style="font-style:italic;"&gt;a&lt;/span&gt; is non-false, the value of &lt;span style="font-style:italic;"&gt;b&lt;/span&gt; if &lt;span style="font-style:italic;"&gt;a&lt;/span&gt; is false and &lt;span style="font-style:italic;"&gt;b&lt;/span&gt; is non-false, or the value of &lt;span style="font-style:italic;"&gt;c&lt;/span&gt; otherwise.&lt;br /&gt;&lt;br /&gt;A &lt;span style="font-style:italic;"&gt;non-false&lt;/span&gt; value in Ruby is anything that's neither &lt;span style="font-style:italic;"&gt;nil&lt;/span&gt;,  nor &lt;span style="font-style:italic;"&gt;false&lt;/span&gt;. Thus, values such as true, 1, 0, "a", [] are all non-false.&lt;br /&gt;&lt;br /&gt;The || operator can be combined with the = operator in a &lt;span style="font-style:italic;"&gt;self-assignment&lt;/span&gt; statement: a ||= &lt;span style="font-style:italic;"&gt;expression&lt;/span&gt;, which is a shorthand for a = a || &lt;span style="font-style:italic;"&gt;expression&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;A statement of that kind is essentially a &lt;span style="font-style:italic;"&gt;conditional initializer&lt;/span&gt;: if &lt;span style="font-style:italic;"&gt;a&lt;/span&gt; is &lt;span style="font-style:italic;"&gt;nil&lt;/span&gt; (i.e., not initialized), initialize it with the value of &lt;span style="font-style:italic;"&gt;expression&lt;/span&gt;. Otherwise, leave it untouched.&lt;br /&gt;&lt;br /&gt;The conditional initialization idiom has at least one interesting usage. Before we get to it, it is important to note that in Ruby every statement returns a value, which means that any statement can be used in place of an expression. For example, one could conceivably do:&lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;(if true then 8 end) + 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ok, on to the example now...&lt;br /&gt;&lt;br /&gt;It is common to have to keep track of lists of items associated with certain &lt;span style="font-style:italic;"&gt;key&lt;/span&gt; values. The obvious way to implement that is with a map of keys to &lt;span style="font-style:italic;"&gt;lists&lt;/span&gt; of values. In Java, the code for adding an element to such structure would typically look like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;void addToList(Object key, Object value)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;List list = (List) this.map.get(key);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (list == null) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      list = new ArrayList();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      this.map.put(key, list);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   list.add(value);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In Ruby, using the conditional initialization idiom, it could be written more compactly as:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def addToList(key, value)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   (@map[key] ||= []) &lt;&lt; value&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The&lt;span style="font-style:italic;"&gt; @map[key] ||= []&lt;/span&gt; piece performs the conditional initialization of the list associated with &lt;span style="font-style:italic;"&gt;key&lt;/span&gt; and the &lt;span style="font-style:italic;"&gt;(...) &lt;&lt; value&lt;/span&gt; part adds the value to the existing or newly created list.&lt;br /&gt;&lt;br /&gt;Ok, ok... you might be thinking, while the Java syntax is more verbose, is certainly more readable. That may be true, but in that case you could still write:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;def addToList(key, value)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   list = (@map[key] ||= [])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   list &lt;&lt; value&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Which is still more compact than in Java but in my opinion does not sacrifice readability.&lt;br /&gt;&lt;br /&gt;Pretty neat, eh?&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/9469017-110678017256880222?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110678017256880222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110678017256880222' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110678017256880222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110678017256880222'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/conditional-initialization-in-ruby.html' title='Conditional initialization in Ruby '/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110671472214966691</id><published>2005-01-25T20:25:00.000-08:00</published><updated>2005-01-25T21:57:25.566-08:00</updated><title type='text'>Babbler</title><content type='html'>Here's a useless cute little program I wrote yesterday, called "Babbler", which creates new text based on how patterns of characters appear in a piece of text used to train the program. It is a Markov generator, which means that it uses the last N (N being the &lt;span style="font-style:italic;"&gt;order&lt;/span&gt;) produced characters to determine which character comes next.&lt;br /&gt;&lt;br /&gt;During training, Babbler analyzes all sequences of 1, 2, ... N characters and records the number of times each shows up in the original text. &lt;br /&gt;&lt;br /&gt;To generate a character, it picks one at random from the set of all characters that may follow the sequence of the last N-1 output characters. The random function honors the frequency distribution of the characters in the source text. If the sequence of N-1 characters hasn't been seen in the source text, the program falls back to a N-2 sequence and so on.  &lt;br /&gt;&lt;br /&gt;Let's see an example. Using the book "The Prince" by Nicolo Machiavelli as training data, here's a fragment generated by an order-1 Babbler:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"gstkln tyeannioi rfa iaeafalrtutficbah tat eri de oesowaitpt neeff p odhi nn .ett borege  r   susnhsardlreneftgbnwauihn"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This is garbage. Essentially, an order-1 Babbler generates random characters based on their frequency in the source text. It gets better with higher order Babblers:&lt;br /&gt;&lt;br /&gt;Order 2: &lt;span style="font-style:italic;"&gt;"pom so owins ase is ibend antusirty hothlest r t nnd cthoath we wnt ony as y sizistaul, cos."&lt;/span&gt;&lt;br /&gt;Order 3: &lt;span style="font-style:italic;"&gt;"sse mays ing per bringet beforgeopers to st yound thus en of wily pir i same of cousembing of the vin to came they caussuccul is much aggrands"&lt;/span&gt;&lt;br /&gt;Order 4: &lt;span style="font-style:italic;"&gt;"runnibaldo, whers, count, and in had the for of meason thirds heles, markable in ought a luccion of france cound seat to blus, on of his rose they againtate trodus, he prince them will for have thing thould by have he abilitated the prince fro"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Here you can see that words start taking a definite english-like form -- they can be &lt;span style="font-style:italic;"&gt;pronounced&lt;/span&gt; in english -- even if they are meaningless. Compare this to an order-4 Babbler trained with Don Quijote, by Cervantes (a well-known Spanish writer):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"no la tale pensigida, porque vaya ena gana, sea desto, y, aun llencio que durmino a mayor de su mores quelevas ciel tien del me dar locura razos mucho malano que alma: no hacer punto de me de sea; pensaminea quijo me hartida"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Lastly, here's an order-5 Babbler for The Prince:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"oned again they always or maste; and not. in 1510. thing except down they have saw the duke, and was defend when case helples. fifteen very were admitted by those offerent him outral; and intered himself anothing his notwith him near again"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The input to Babbler is a &lt;span style="font-style:italic;"&gt;tokenizer&lt;/span&gt; object, which must implement the each() method. This allows for babbling randomly selected characters (what I've shown you so far) or words. Here's an example of an order-4 Babbler that uses entire words as tokens:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"should now take part; but nothing being concluded, Oliverotto da Fermo was sent to propose that if the duke wished to undertake an expedition against Tuscany they were ready; if he did not wish that the fortresses, which he did not recognize any need for doing so, he begged Castruccio to pardon the other members of his family by reason of the wrongs recently inflicted upon them."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you're interested, here's the source: &lt;a href="http://clans.gameclubcentral.com/shoot/babbler.rb"&gt;babbler.rb&lt;/a&gt;. It's written in Ruby, but may contain many Java&lt;span style="font-style:italic;"&gt;isms&lt;/span&gt; due to the fact I'm still getting used to the language (I started learning Ruby this weekend and this is my version of a "Hello World" -- on steroids)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110671472214966691?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110671472214966691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110671472214966691' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110671472214966691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110671472214966691'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/babbler.html' title='Babbler'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110637381126341572</id><published>2005-01-21T21:58:00.000-08:00</published><updated>2005-01-22T20:55:00.243-08:00</updated><title type='text'>Emulating keystrokes in Windows</title><content type='html'>One of the core functions in &lt;a href="http://clans.gameclubcentral.com/shoot"&gt;Shoot&lt;/a&gt;, a voice command program I wrote a couple of years ago, is the ability to emulate key presses programmatically. &lt;br /&gt;&lt;br /&gt;There is a fairly straightforward way to do this in Windows 2000/XP, via the SendInput Win32 function. In Windows 98/ME things are somewhat more complicated: SendInput inserts the keystrokes in the Windows event queue, but DirectInput bypasses it and hooks directly into the keyboard driver. &lt;br /&gt;&lt;br /&gt;As a result, any keystroke sent via SendInput is completely ignored by DirectInput applications. Pretty much every modern Windows-based game uses DirectInput, the main target for Shoot. The solution is to implement a Virtual Device Driver (VxD) that inserts the keystrokes directly into the keyboard driver buffer, and that is what I ended up doing for Shoot. &lt;br /&gt;&lt;br /&gt;Here's how to use the SendInput function from C#. I stripped all the Win98/ME-related code. Not only would it make the code below significantly more complex, but it's probably useless by now. Who's using Win 98, anyway? Not even Microsoft supports it anymore :)&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;[StructLayout(LayoutKind.Sequential)]&lt;br /&gt;private struct KEYBOARD_INPUT {&lt;br /&gt;public uint type;&lt;br /&gt;public ushort vk;&lt;br /&gt;public ushort scanCode;&lt;br /&gt;public uint flags;&lt;br /&gt;public uint time;&lt;br /&gt;public uint extrainfo;&lt;br /&gt;public uint padding1;&lt;br /&gt;public uint padding2;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[DllImport("User32.dll")]&lt;br /&gt;private static extern uint SendInput(uint numberOfInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst=1)] KEYBOARD_INPUT[] input, int structSize);&lt;br /&gt;&lt;br /&gt;void press(int scanCode)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;sendKey(scanCode, true);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void release(int scanCode)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;sendKey(scanCode, false);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void sendKey(int scanCode, bool press)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;    KEYBOARD_INPUT[] input = new KEYBOARD_INPUT[1];&lt;br /&gt;&amp;nbsp;&amp;nbsp;    input[0] = new KEYBOARD_INPUT();&lt;br /&gt;&amp;nbsp;&amp;nbsp;    input[0].type = INPUT_KEYBOARD;&lt;br /&gt;&amp;nbsp;&amp;nbsp;    input[0].flags = KEY_SCANCODE;&lt;br /&gt;   &lt;br /&gt;&amp;nbsp;&amp;nbsp;    if ((scanCode &amp; 0xFF00) == 0xE000) { // extended key?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        input[0].flags |= KEY_EXTENDED;&lt;br /&gt;&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;   &lt;br /&gt;&amp;nbsp;&amp;nbsp;    if (press) { // press?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        input[0].scanCode = (ushort) (scanCode &amp; 0xFF);&lt;br /&gt;&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;&amp;nbsp;&amp;nbsp;    else { // release?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        input[0].scanCode = scanCode;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        input[0].flags |= KEY_UP;&lt;br /&gt;&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;    uint result = SendInput(1, input, Marshal.SizeOf(input[0]));&lt;br /&gt;   &lt;br /&gt;&amp;nbsp;&amp;nbsp;    if (result != 1) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        throw new Exception("Could not send key: " + scanCode);&lt;br /&gt;&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;}&lt;br /&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/9469017-110637381126341572?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110637381126341572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110637381126341572' title='21 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110637381126341572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110637381126341572'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/emulating-keystrokes-in-windows.html' title='Emulating keystrokes in Windows'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110632564228726276</id><published>2005-01-21T08:23:00.000-08:00</published><updated>2005-01-21T09:17:15.986-08:00</updated><title type='text'>Java tip #1 </title><content type='html'>Working with Swing JTables can be tricky. Working with custom cell editors is even trickier. Here's a tip that may save you some time and frustration.&lt;br /&gt;&lt;br /&gt;This is a custom cell editor (based on a text field) that will automatically highlight its contents as soon as it is becomes active and save the user from having to select the text with the mouse or with the all-too-common "home - shift+end" key sequence.&lt;br /&gt;&lt;br /&gt;The trick is to select the text &lt;span style="font-style: italic;"&gt;after&lt;/span&gt; the editor gets focus. Otherwise, the JTextField object will ignore the request.&lt;br /&gt;&lt;br /&gt;Here's the code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;private class CustomTableCellEditor&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;extends DefaultCellEditor&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;public CustomTableCellEditor()&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   // use a JTextField as the actual editor&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   super(new JTextField());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   final JTextField editor = (JTextField) getComponent();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   editor.setName("Table.editor");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   editor.setBorder(new LineBorder(Color.black));&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   // listen for focusing events&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   editor.addFocusListener(new FocusListener()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;     public void focusGained(FocusEvent e)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;     {     &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;       // now is the time to select the text in the JTextField&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;              editor.selectAll();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;     }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;          public void focusLost(FocusEvent e) { }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      });&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)&lt;br /&gt;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   final JTextField textField = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      Runnable task = new Runnable() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;     public void run()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;             // set the focus on the JTextField&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;       textField.requestFocusInWindow();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;     }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   };&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   SwingUtilities.invokeLater(task);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   return textField;&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&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/9469017-110632564228726276?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110632564228726276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110632564228726276' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110632564228726276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110632564228726276'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/java-tip-1.html' title='Java tip #1 '/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110626300911448399</id><published>2005-01-20T15:10:00.000-08:00</published><updated>2005-01-20T22:06:17.436-08:00</updated><title type='text'>GCHQ challenge</title><content type='html'>The GCHQ posted the following &lt;a href="http://www.gchq.gov.uk/codebreaking/"&gt;challenge&lt;/a&gt; a couple of months ago:&lt;br /&gt;&lt;br /&gt;What is the connection between the men in the first list and the women in the second list? Which man pairs with which woman? And what is the hidden quotation?&lt;br /&gt;&lt;br /&gt;&lt;table border="0" cellpadding="10" cellspacing="0" height="340"&gt;   				  &lt;tbody&gt;&lt;tr&gt; &lt;td valign="top"&gt;  					  						 						&lt;div&gt;&lt;b&gt;MEN&lt;/b&gt;&lt;/div&gt;  						&lt;div&gt;KCRVKXHL EUJDXZ&lt;/div&gt;  						&lt;div&gt;WKNJVWL GSWOXU&lt;/div&gt;  						&lt;div&gt;HYUE WREEYCS&lt;/div&gt;  						&lt;div&gt;QFDX ORNQTP&lt;/div&gt;  						&lt;div&gt;VTWMAC UEIIML&lt;/div&gt;  						&lt;div&gt;OFIIPTYX LYIJ&lt;/div&gt;  						&lt;div&gt;ZGRT BPDIIRNN&lt;/div&gt;  						&lt;div&gt;XCT GSXXJYUQ&lt;/div&gt;  						&lt;div&gt;RNBTCNP TCOSHNM&lt;/div&gt;  						&lt;div&gt;XIVL VFBD&lt;/div&gt;  						&lt;div&gt;NRIKUSL UIQORMDB&lt;/div&gt;  						&lt;div&gt;UFIV WKXXZY&lt;/div&gt;  						&lt;div&gt;DYFJN WCLEQPJ&lt;/div&gt;  						&lt;div&gt;LVZD CONKLNFK&lt;/div&gt;  						&lt;div&gt;PZSS TEBBMJ&lt;/div&gt;  						&lt;div&gt;BZGZD A'GAANZ&lt;/div&gt;  						&lt;div&gt;JRFJWRI XFCS&lt;/div&gt;  						&lt;div&gt;QJAMDU ZWWVDU&lt;/div&gt;  						&lt;div&gt;GMTHYL IKUBGMFPTPSSPM&lt;/div&gt;  						&lt;div&gt;KEZHQ WSNIEC&lt;/div&gt;  					&lt;/td&gt; &lt;td valign="top"&gt;  						&lt;div&gt;&lt;b&gt;WOMEN&lt;/b&gt;&lt;/div&gt;  						&lt;div&gt;TVFAMI WVYVTT&lt;/div&gt;  						&lt;div&gt;KHP FNWHQBEV&lt;/div&gt;  						&lt;div&gt;MTJXMG EHXJRDT&lt;/div&gt;  						&lt;div&gt;ORERC VIUWFNUE&lt;/div&gt;  						&lt;div&gt;AIKUSBS EHSMKHNR&lt;/div&gt;  						&lt;div&gt;UQPIDJX HEXID&lt;/div&gt;  						&lt;div&gt;TZMMDR WDNCRM&lt;/div&gt;  						&lt;div&gt;ECWHX YCMBXA&lt;/div&gt;  						&lt;div&gt;LRNU FHZOHVN&lt;/div&gt;  						&lt;div&gt;YVTLG UGZVYNHT&lt;/div&gt;  						&lt;div&gt;YAERFI KFXBARV&lt;/div&gt;  						&lt;div&gt;OUGEUDLRZ EZBVJDR&lt;/div&gt;  						&lt;div&gt;CQMBSVDD LNYMICCNI&lt;/div&gt;  						&lt;div&gt;DGOFBL AGUCZD&lt;/div&gt;  						&lt;div&gt;AQSEWKC XFIWFSYK&lt;/div&gt;  						&lt;div&gt;RKUUC VHMPUUPT&lt;/div&gt;  						&lt;div&gt;CZNTBXD CFDNFE&lt;/div&gt;  						&lt;div&gt;OSXFSXCZ XBZGCXDUXA&lt;/div&gt;  						&lt;div&gt;BQKDVGBOJ OVIQXW&lt;/div&gt;  						&lt;div&gt;CWUIFBLSK HSOGSB&lt;/div&gt;&lt;/td&gt;  				  &lt;/tr&gt;  				&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;I've already solved it, but I'm not going to tell you the answer yet. I'll post it here after the window for submitting the solution to GCHQ has closed.&lt;br /&gt;&lt;br /&gt;What are you waiting for, get those brain cells working!&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/9469017-110626300911448399?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110626300911448399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110626300911448399' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110626300911448399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110626300911448399'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/gchq-challenge.html' title='GCHQ challenge'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110616914730375140</id><published>2005-01-19T12:52:00.000-08:00</published><updated>2005-01-19T13:47:46.313-08:00</updated><title type='text'>Garmin iQue 3600a</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;img src="http://www.garmin.com/products/iQue3600a/graphics/pt-ique3600aSmall.jpg" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Garmin has unveiled a new GPS gadget, the &lt;a href="http://www.garmin.com/products/iQue3600a/"&gt;iQue 3600a.&lt;/a&gt; It's a Palm device with GPS capabilities and a bunch of aviation-related software. It looks great, if you ask me, although it's a little bit pricey at $1100.&lt;br /&gt;&lt;br /&gt;I've been on the lookout for a GPS device lately, and the best candidate so far was the &lt;a href="http://www.garmin.com/products/gpsmap296/"&gt;Garmin GPSMAP 296&lt;/a&gt;. The iQue has all the functions a regular Palm has, such as adress book and calendar, which, in my opinion tilt the balance against the 296 (plus the fact that the latter costs $1700).&lt;br /&gt;&lt;br /&gt;From the specs I couldn't see anything significant in the 296 that's missing in the iQue. In fact the iQue features a nifty 16-bit color screen (65536 colors) vs. 296's 8-bit (256 colors) screen.&lt;br /&gt;&lt;br /&gt;For in-cockpit and outdoors use the 296 may be more robust (better shock resistance, weather-proof, longer battery life), but for regular day-to-day use, the iQue seems like a great contender.&lt;br /&gt;&lt;br /&gt;Finally, I'm sure Garmin will make an SDK available for the 3600a soon. It's &lt;a href="https://www.garmin.com/DeveloperZone/"&gt;available&lt;/a&gt; for the 3600, and I'd be surprised if it doesn't already support the 3600a, so it may just be a matter of certification. The device runs PalmOS and the iQue 3600 page claims that all GPS-related functions are available to third-party software. Sweeeet!&lt;br /&gt;&lt;span class="down" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110616914730375140?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110616914730375140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110616914730375140' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110616914730375140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110616914730375140'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2005/01/garmin-ique-3600a.html' title='Garmin iQue 3600a'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110291429685310757</id><published>2004-12-12T20:36:00.000-08:00</published><updated>2004-12-12T21:31:06.600-08:00</updated><title type='text'>out for a spin</title><content type='html'>I took a couple of friends flying yesterday. It was a beatiful day, after a few weeks of bad weather. That meant, of course, that everybody had to come up with the same idea.&lt;br /&gt;&lt;br /&gt;The airport was extremely crowded. We were 3rd in the takeoff sequence, with at least 4 airplanes waiting after us. 3 airplanes landed in the short period before our turn came up.&lt;br /&gt;&lt;br /&gt;We left the airport to the north and got a "traffic 9 o'clock, 1 mile" advise from the tower before leaving Addison's airspace. Figuring the friendly skies would be as crowded as the ground, I turned my radio to the approach frequency to listen for nearby traffic as soon as we were clear of Class D airspace.&lt;br /&gt;&lt;br /&gt;We cruised around for a bit, keeping a watchful 3 sets of eyes (it's always a good idea to have your passengers look out for traffic as well) on the space around us. When flying under VFR (visual flight rules), it's the pilot's responsibility to see and avoid other aircraft, even when talking to ground-based controllers. The may occasionally advise about nearby traffic, but they are not required to do so. After all, they are not liable if you have an intimate encounter with another plane.&lt;br /&gt;&lt;br /&gt;We did, indeed, come across a few other airplanes and had to maneuver to avoid getting too close to them. Other than that, our short trip was peaceful and uneventful.&lt;br /&gt;&lt;br /&gt;As always, I really enjoyed the flight, which was a welcome break from the more demanding aerobatic training I've been working on for the past couple of months.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110291429685310757?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110291429685310757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110291429685310757' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110291429685310757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110291429685310757'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2004/12/out-for-spin.html' title='out for a spin'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110263225144769039</id><published>2004-12-09T14:35:00.000-08:00</published><updated>2004-12-09T14:57:56.730-08:00</updated><title type='text'>learning to cherish</title><content type='html'>I took this picture a few months ago. Needless to say, it's one of my favorites.&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://clans.gameclubcentral.com/shoot/manos.jpg" width="600" /&gt;&lt;br /&gt;&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110263225144769039?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110263225144769039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110263225144769039' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110263225144769039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110263225144769039'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2004/12/learning-to-cherish.html' title='learning to cherish'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110262244973472809</id><published>2004-12-09T11:28:00.000-08:00</published><updated>2005-01-20T09:21:27.146-08:00</updated><title type='text'>backing up digital pictures</title><content type='html'>I have a 6 megapixel digital camera. Each picture I take uses up around 6 mb of disk space (at the highest quality, RAW format) and I've already shot almost a thousand.&lt;br /&gt;&lt;br /&gt;Backing up that amount of data is becoming a royal pain in the butt. CDs are already too small. DVDs will soon be, too, at the rate at which I'm taking pictures. As a temporary measure, I'm storing all the images in my iPod and I will probably have to get an external drive.&lt;br /&gt;&lt;br /&gt;My main concern is that soon I'm not going to be able to keep all my pictures in my puny laptop hard drive. I may need to get two external drives, instead, for primary and backup storage.&lt;br /&gt;&lt;br /&gt;Or how does a RAID-5 disk array sound?&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110262244973472809?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110262244973472809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110262244973472809' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110262244973472809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110262244973472809'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2004/12/backing-up-digital-pictures.html' title='backing up digital pictures'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110254715265966683</id><published>2004-12-08T14:56:00.000-08:00</published><updated>2004-12-08T15:08:09.266-08:00</updated><title type='text'>the great playlist meme of '04</title><content type='html'>Here are the instructions:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;   Open up the music player on your computer.&lt;/li&gt;   &lt;li&gt;Set it to play your entire music collection.&lt;/li&gt;   &lt;li&gt;Hit the "shuffle" command.&lt;/li&gt;   &lt;li&gt;Tell us the title of the next ten songs that show up (with their musicians), no matter how embarrassing. That's right, no skipping that Carpenters tune that will totally destroy your hip credibility. It's time for total musical honesty. Write it up in your blog or journal and link back to at least a couple of the other sites where you saw this.&lt;/li&gt;   &lt;li&gt;If you get the same artist twice, you may skip the second (or third, or etc.) occurrences. You don't have to, but since randomness could mean you end up with a list of ten song with five artists, you can if you'd like.&lt;/li&gt; &lt;/ol&gt; Here's my list:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Down To The Waterline - Dire Straits&lt;/li&gt;   &lt;li&gt;Cerca De La Revolución - Charly García&lt;/li&gt;   &lt;li&gt;Entre Caníbales - Soda Stereo&lt;/li&gt;   &lt;li&gt;I Can't Tell You Why - The Eagles&lt;/li&gt;   &lt;li&gt;Englishman In New York - Sting&lt;/li&gt;   &lt;li&gt;Stuck In A Moment You Can't Get Out Of - U2&lt;/li&gt;   &lt;li&gt;Quizas Porque - Sui Generis&lt;/li&gt;   &lt;li&gt;Big Shot - Billy Joel&lt;/li&gt;   &lt;li&gt;Que Hago Ahora (Dónde Pongo Lo Hallado) - Silvio Rodriguez&lt;/li&gt;   &lt;li&gt;Pennyroyal Tea - Nirvana&lt;/li&gt; &lt;/ol&gt; via &lt;a href="http://www.dynamicobjects.com/d2r"&gt;Diego&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110254715265966683?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110254715265966683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110254715265966683' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110254715265966683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110254715265966683'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2004/12/great-playlist-meme-of-04.html' title='the great playlist meme of &apos;04'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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-9469017.post-110253663944454911</id><published>2004-12-08T12:10:00.000-08:00</published><updated>2005-01-21T08:56:31.353-08:00</updated><title type='text'>Stack trace translation using annotations</title><content type='html'>Code generators and compilers that use Java as an intermediate language (e.g, JSP compilers) can take advantage of the new Java annotations feature for translating stack traces.&lt;br /&gt;&lt;br /&gt;Why is this necessary? Any runtime error in the form of an exception will have its stack trace expressed in terms of the intermediate java code. Troubleshooting the problem could become a nightmare, unless the line and number information is presented in the context of the components and methods originally written by the developer.&lt;br /&gt;&lt;br /&gt;In simple terms, the idea is to place line number information in metadata blocks in every class generated by the compiler. This information is accessed during runtime to interpret and translate stack traces back into something the developer will understand.&lt;br /&gt;&lt;br /&gt;Let's consider a hypothetical component called "MyObj" that has two methods: "methodA" and "methodB". Here's an example of what the intermediate Java code might look like:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;@TranslationTable(lines = {&lt;br /&gt;&amp;nbsp;&amp;nbsp;@Entry(line=11,component="MyObj",method="methodA",sourceLine=241),&lt;br /&gt;&amp;nbsp;&amp;nbsp;@Entry(line=12,component="MyObj",method="methodA",sourceLine=247),&lt;br /&gt;&amp;nbsp;&amp;nbsp;@Entry(line=13,component="MyObj",method="methodA",sourceLine=249),&lt;br /&gt;&amp;nbsp;&amp;nbsp;@Entry(line=18,component="MyObj",method="methodB",sourceLine=340)&lt;br /&gt;})&lt;br /&gt;public class AutogeneratedObject&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;void autogeneratedMethod1()&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int a = 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int b = 2;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; autogeneratedMethod2();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;void autogeneratedMethod2()&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new RuntimeException();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The metadata block is made of a tag (@TranslationTable) that contains a list of sub-tags (@Entry). Each entry represents a line of significant code in the generated class. Information about the line number in the generated class and the name of the original component, method and line number it maps to are stored in each entry.&lt;br /&gt;&lt;br /&gt;Here's the definition of the Entry tag:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;import java.lang.annotation.*;&lt;br /&gt;&lt;br /&gt;@Retention(RetentionPolicy.RUNTIME)&lt;br /&gt;public @interface Entry&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;int line();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;String component();&lt;br /&gt;&amp;nbsp;&amp;nbsp;String method() default "[unknown]";&lt;br /&gt;&amp;nbsp;&amp;nbsp;int sourceLine();&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And here's the TranslationTable tag:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;import java.lang.annotation.*;&lt;br /&gt;&lt;br /&gt;@Retention(RetentionPolicy.RUNTIME)&lt;br /&gt;@Target(ElementType.TYPE)&lt;br /&gt;public @interface TranslationTable&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;Entry[] lines();&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The stack trace translator takes each stack frame, obtains the associated class, queries the class for it's TranslationTable metadata and looks up the TranslationTableEntry for the line reported by the stack frame.&lt;br /&gt;&lt;br /&gt;This is what the stack trace translator might look like. I know, I know, the implementation very inefficient (linear traversals of the translation tables, no caching)... I'm just trying to make a point here :)&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;StackTraceElement[] translate(StackTraceElement[] elements)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;List&lt;stacktraceelement&gt; result = new ArrayList&lt;stacktraceelement&gt;();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;for (StackTraceElement element : elements) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    Class clazz = Class.forName(element.getClassName());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    TranslationTable table = (TranslationTable) clazz.getAnnotation(TranslationTable.class);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    boolean found = false;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    if (table != null) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      for (Entry line : table.lines()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        if (line.line() == element.getLineNumber()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;          result.add(new StackTraceElement(line.component(), line.method(), line.component(), line.sourceLine()));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;          found = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;          break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;        }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    if (table == null || !found) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;      result.add(element);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (ClassNotFoundException e) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;     e.printStackTrace();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;return result.toArray(new StackTraceElement[0]);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If you're not in the mood for trying out the code, I already did it for you :). Here's a regular Java stack trace:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;java.lang.RuntimeException&lt;br /&gt;&amp;nbsp;&amp;nbsp;at AutogeneratedObject.autogeneratedMethod2(Test.java:18)&lt;br /&gt;&amp;nbsp;&amp;nbsp;at AutogeneratedObject.autogeneratedMethod1(Test.java:13)&lt;br /&gt;&amp;nbsp;&amp;nbsp;at Test.main(Test.java:25)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And the translated version:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;MyObj.methodB(340)&lt;br /&gt;MyObj.methodA(249)&lt;br /&gt;Test.main(25)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110253663944454911?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://split-s.blogspot.com/feeds/110253663944454911/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9469017&amp;postID=110253663944454911' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110253663944454911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110253663944454911'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2004/12/stack-trace-translation-using.html' title='Stack trace translation using annotations'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9469017.post-110254798401808843</id><published>2004-12-08T08:16:00.000-08:00</published><updated>2004-12-08T15:30:16.273-08:00</updated><title type='text'>split-s</title><content type='html'>... just make sure you're &lt;a href="http://www.f-16.net/f-16_news_article968.html"&gt;high enough&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://clans.gameclubcentral.com/shoot/f16.jpg" width="300" /&gt;&lt;br /&gt;&lt;font size="-1"&gt;Photo by SSgt Bennie J. Davis III&lt;br /&gt;Still Photographer, USAF&lt;/font&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9469017-110254798401808843?l=split-s.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110254798401808843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9469017/posts/default/110254798401808843'/><link rel='alternate' type='text/html' href='http://split-s.blogspot.com/2004/12/split-s.html' title='split-s'/><author><name>Martin</name><uri>http://www.blogger.com/profile/08718317252176743227</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></entry></feed>
