<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Random Hacks</title>
    <link>http://www.randomhacks.net/</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Technology and Other Fun Stuff</description>
    <item>
      <title>Write a 32-line chat client using Ruby, AMQP &amp;amp; EventMachine (and a GUI using Shoes)</title>
      <description>&lt;p&gt;Have you ever considered using instant messages to communicate between programs? You can do this using &lt;a href="http://www.jabber.org/"&gt;Jabber&amp;#8217;s XMPP protocol&lt;/a&gt;, of course. But it&amp;#8217;s also worth taking a look at &lt;a href="http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol"&gt;AMQP&lt;/a&gt;, a distributed messaging protocol first used at JPMorgan Chase. AMQP is fast, easy to use, and implemented by at least 4 open source servers.&lt;/p&gt;

&lt;p&gt;To try it out, install the excellent &lt;a href="http://github.com/tmm1/amqp/tree/master"&gt;Ruby AMQP bindings&lt;/a&gt;, and set up the &lt;a href="http://www.rabbitmq.com/"&gt;RabbitMQ&lt;/a&gt; server (which is written in Erlang using Mnesia). On a Mac, you might do something like this:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_sh "&gt;sudo gem install amqp
sudo port install python25 rabbitmq-server
sudo rabbitmq-server&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once your server is running, save the following code as &lt;code&gt;chat.rb&lt;/code&gt;:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;rubygems&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;gem&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;amqp&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;mq&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;
  &lt;span class="constant"&gt;STDERR&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Usage: &lt;span class="expr"&gt;#{$0}&lt;/span&gt; &amp;lt;channel&amp;gt; &amp;lt;nick&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="ident"&gt;exit&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="global"&gt;$channel&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="global"&gt;$nick&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;

&lt;span class="constant"&gt;AMQP&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:host&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;localhost&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="global"&gt;$chat&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MQ&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;topic&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;chat&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;

  &lt;span class="comment"&gt;# Print any messages on our channel.&lt;/span&gt;
  &lt;span class="ident"&gt;queue&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MQ&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;queue&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="global"&gt;$nick&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;queue&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;chat&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:key&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="global"&gt;$channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;queue&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;subscribe&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;msg&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;msg&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{$nick}&lt;/span&gt;:&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;
      &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;msg&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="comment"&gt;# Forward console input to our channel.&lt;/span&gt;
  &lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;KeyboardInput&lt;/span&gt;
    &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;EM&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Protocols&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;LineText2&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;receive_line&lt;/span&gt; &lt;span class="ident"&gt;data&lt;/span&gt;
      &lt;span class="global"&gt;$chat&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;publish&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{$nick}&lt;/span&gt;: &lt;span class="expr"&gt;#{data}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
                    &lt;span class="symbol"&gt;:routing_key&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="global"&gt;$channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="constant"&gt;EM&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;open_keyboard&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;KeyboardInput&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, run copies in two different terminals:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_sh "&gt;ruby chat.rb channel_1 sarah
ruby chat.rb channel_1 joe&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Everything you type into one terminal will be relayed to the other.&lt;/p&gt;

&lt;h3&gt;How it works&lt;/h3&gt;

&lt;p&gt;The following line creates a &lt;em&gt;topic exchange&lt;/em&gt; named &amp;#8220;chat&amp;#8221;: &lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="global"&gt;$chat&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MQ&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;topic&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;chat&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A topic exchange allows many-to-many communication.  Here, we bind a listener to our exchange, and ask to receive all messages tagged with our channel name:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;queue&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;chat&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:key&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="global"&gt;$channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that &lt;code&gt;:key&lt;/code&gt; may be hierarchical, and it may contain wildcards. To write data to our topic exchange, we use &lt;code&gt;publish&lt;/code&gt;:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="global"&gt;$chat&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;publish&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{$nick}&lt;/span&gt;: &lt;span class="expr"&gt;#{data}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
              &lt;span class="symbol"&gt;:routing_key&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="global"&gt;$channel&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Our keyboard input is processed using &lt;a href="http://rubyeventmachine.com/"&gt;EventMachine&lt;/a&gt;, a Ruby library for writing high-performance, multi-protocol servers. It&amp;#8217;s very similar to Python&amp;#8217;s &lt;a href="http://twistedmatrix.com/trac/"&gt;Twisted&lt;/a&gt; library, though it has less documentation and support for fewer protocols.&lt;/p&gt;

&lt;p&gt;We use EventMachine&amp;#8217;s &lt;code&gt;EM.open_keyboard&lt;/code&gt; to create a asynchronous keyboard input channel, and we use &lt;code&gt;EM::Protocols::LineText2&lt;/code&gt; to treat the keyboard input as a line-oriented protocol.&lt;/p&gt;

&lt;h3&gt;Adding a Shoes GUI&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://shoooes.net/"&gt;Shoes&lt;/a&gt; is an eccentric, entertaining, and highly-portable GUI library by &lt;a href="http://whytheluckystiff.net/"&gt;_why the lucky stiff&lt;/a&gt;. With a certain amount of grotesque kludging (and some pointers from &amp;#8220;s1kx&amp;#8221; on the #shoes IRC channel), I managed to get the Mac version of Shoes to talk to EventMachine. You may find that this code fails strangely on your computer. Honestly, I don&amp;#8217;t know anything about Shoes. And I&amp;#8217;m doing some pretty bad things with threads.&lt;/p&gt;

&lt;p&gt;First, the pretty pictures:&lt;/p&gt;

&lt;p&gt;&lt;img src="/files/shoes-chat.png" width="318" height="297" /&gt;&lt;/p&gt;

&lt;p&gt;Next, the code:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Shoes&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;setup&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;gem&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;amqp&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;mq&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="global"&gt;$app&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Shoes&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;app&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:width&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;256&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;background&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;gradient&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;#CFF&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;#FFF&lt;/span&gt;&lt;span class="punct"&gt;'))&lt;/span&gt;
  &lt;span class="attribute"&gt;@output&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;stack&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:margin&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;nick&lt;/span&gt; &lt;span class="ident"&gt;str&lt;/span&gt;
    &lt;span class="ident"&gt;span&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;str&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:stroke&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;red&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;display&lt;/span&gt; &lt;span class="ident"&gt;text&lt;/span&gt;
    &lt;span class="attribute"&gt;@output&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
      &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^([^:]+): (.*)$&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;
        &lt;span class="ident"&gt;para&lt;/span&gt; &lt;span class="ident"&gt;nick&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{$1}&lt;/span&gt;: &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;),&lt;/span&gt; &lt;span class="global"&gt;$2&lt;/span&gt;
      &lt;span class="keyword"&gt;else&lt;/span&gt;
        &lt;span class="ident"&gt;para&lt;/span&gt; &lt;span class="ident"&gt;text&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="keyword"&gt;begin&lt;/span&gt;
    &lt;span class="constant"&gt;AMQP&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:host&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;localhost&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
      &lt;span class="constant"&gt;MQ&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;topic&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;chat&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
      &lt;span class="ident"&gt;queue&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MQ&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;queue&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;shoes&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
      &lt;span class="ident"&gt;queue&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;chat&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
      &lt;span class="ident"&gt;queue&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;subscribe&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;msg&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
        &lt;span class="global"&gt;$app&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;display&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;msg&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;rescue&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;e&lt;/span&gt;
    &lt;span class="comment"&gt;# Try to report at least _some_ errors&lt;/span&gt;
    &lt;span class="comment"&gt;# where we'll be able to see them.&lt;/span&gt;
    &lt;span class="global"&gt;$app&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;display&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that the GUI client listens to all channels simultaneously, because it doesn&amp;#8217;t pass a &lt;code&gt;:key&lt;/code&gt; to &lt;code&gt;bind&lt;/code&gt;. And when writing code to run in a Shoes background thread, don&amp;#8217;t expect to see any error messages.&lt;/p&gt;

&lt;h3&gt;Learning more about AMQP&lt;/h3&gt;

&lt;p&gt;The &lt;a href="http://amqp.rubyforge.org/"&gt;Ruby AMQP documentation page&lt;/a&gt; has a good list of papers, magazine articles, and other background material on AMQP.&lt;/p&gt;</description>
      <pubDate>Fri, 08 May 2009 18:06:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:1119e725-a4de-4e5b-a211-8405e7490eeb</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2009/05/08/chat-client-ruby-amqp-eventmachine-shoes</link>
      <category>Ruby</category>
      <category>MQ</category>
      <category>AMQP</category>
      <category>EventMachine</category>
      <category>Shoes</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/620</trackback:ping>
    </item>
    <item>
      <title>Financial crisis background and Munger on the banks</title>
      <description>&lt;p&gt;Charlie Munger is the long-time partner of Warren Buffet. Of the two, he&amp;#8217;s the more politically conservative. Their company, Berkshire Hathaway, has recently bought big stakes in several of the better-off investment banks.&lt;/p&gt;

&lt;p&gt;Recently, &lt;a href="http://www.bloomberg.com/apps/news?pid=20601087&amp;amp;sid=aRGmF1WqsCgA&amp;amp;refer=home"&gt;Munger sharply criticized the management of the investment banks&lt;/a&gt;, saying they&amp;#8217;ve grown too politically powerful. The key quote:&lt;/p&gt;

&lt;blockquote&gt;“We need to remove from the investment banking and the commercial banking industries a lot of the practices and prerogatives that they have so lovingly possessed,” Munger said. “If they are too big to fail, they are too big to be allowed to be as gamey and venal as they’ve been &amp;#8211; and as stupid as they’ve been.” (Bloomberg.com, via &lt;a href="http://baselinescenario.com/2009/05/05/all-about-optics-predicting-stress-test-outcomes/"&gt;Baseline Scenario&lt;/a&gt;.)&lt;/blockquote&gt;

&lt;p&gt;What does the bankers&amp;#8217; stupidity have to do with the usual themes of this blog? Well, much of the crisis comes down to bad probability calculations: the big banks have been treating highly correlated events as though they were independent events.&lt;/p&gt;

&lt;p&gt;Some good background material on the crisis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A neat visual metaphor for CDOs: &lt;a href="http://vimeo.com/1876936?pg=embed&amp;amp;sec="&gt;Filling a tower of champagne glasses.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.khanacademy.org/"&gt;Khan Academy videos on the financial crisis&lt;/a&gt; (middle column, halfway down).&lt;/li&gt;
&lt;li&gt;A confession by the programmer who wrote &lt;a href="http://nymag.com/news/business/55687/"&gt;the software that encouraged this whole mess&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description>
      <pubDate>Tue, 05 May 2009 09:36:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:5fc8fe5a-4afd-42c0-b21a-6a80077dc924</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2009/05/05/financial-crisis</link>
      <category>Probability</category>
      <category>Finance</category>
      <category>Politics</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/617</trackback:ping>
    </item>
    <item>
      <title>Designing programs with RSpec and Cucumber (plus a book recomendation)</title>
      <description>&lt;p&gt;Over the last couple of years, I&amp;#8217;ve occasionally written Ruby programs using &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; and (more recently) &lt;a href="http://rspec.info/"&gt;Cucumber&lt;/a&gt;. These two tools are inspired by &lt;a href="http://www.amazon.com/Test-Driven-Development-Addison-Wesley-Signature/dp/0321146530"&gt;Test Driven Development&lt;/a&gt; (TDD), a school of thought which says you should write unit tests &lt;em&gt;before&lt;/em&gt; implementing a feature. &lt;/p&gt;

&lt;p&gt;When doing TDD, you work inwards from the interface to the implementation. You start by writing a test case against the interface you &lt;em&gt;wish&lt;/em&gt; you had, and then you make that test case work. This is a subtle shift in how you approach a design problem, but it frequently results in beautiful APIs. (And you also get a fully automated test suite for your software, liberating you to make much larger changes without fear of breaking things.)&lt;/p&gt;

&lt;h3&gt;The problem with the word &amp;#8220;test&amp;#8221;&lt;/h3&gt;

&lt;p&gt;Unfortunately, the name &amp;#8220;Test Driven Development&amp;#8221; is misleading. Most folks think of &amp;#8220;testing&amp;#8221; as something you do &lt;em&gt;after&lt;/em&gt; development is complete. But TDD is really more of a design activity&amp;#8212;you&amp;#8217;re specifying how your APIs should work &lt;em&gt;before&lt;/em&gt; you actually start coding.&lt;/p&gt;

&lt;p&gt;Dan North spent some time struggling to teach developers about TDD. After a while, he decided that the main barrier to understanding was the word &amp;#8220;test.&amp;#8221; He proposed replacing TDD with &lt;a href="http://dannorth.net/introducing-bdd"&gt;Behavior Driven Development&lt;/a&gt; (BDD), and he started referring to unit tests as &amp;#8220;specifications.&amp;#8221;&lt;/p&gt;

&lt;p&gt;In the Ruby community, the most popular BDD tool is &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;. Using RSpec, you might specify an API something like this:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;describe&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;simplify_name&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;should convert all letters to lowercase&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;simplify_name&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;AbC&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;).&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;abc&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;should remove everything but letters and spaces&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;simplify_name&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; Joe Smith 3 -+&lt;span class="escape"&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;).&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;joe smith&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After writing this specification, you would then go ahead and implement &lt;code&gt;simplify_name&lt;/code&gt;. And from then on, whenever you changed your program, you could automatically check it against this specification.&lt;/p&gt;

&lt;h3&gt;Using specifications to communicate with clients and users&lt;/h3&gt;

&lt;p&gt;By itself, RSpec is mostly useful for programmers. Sure, a specification looks a lot like English. But would you really want to show it to an end user?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://rspec.info/"&gt;Cucumber&lt;/a&gt; goes one step further. Instead of using code to specify how an API should work, it uses plain text to describe how a &lt;em&gt;user interface&lt;/em&gt; should work. For example:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_cucumber "&gt;Feature: Log in and out
  As an administrator
  I want to restrict access to certain portions of my site
  In order to prevent users from changing the content

  Scenario: Logging in
    Given I am not logged in as an administrator
    When I go to the administrative page
    And I fill in the fields
      | Username | admin  |
      | Password | secret |
    And I press &amp;quot;Log in&amp;quot;
    Then I should be on the administrative page
    And I should see &amp;quot;Log out&amp;quot;

  Scenario: Logging out
    ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;#8217;s the neat part: This specification is actually an executable program. Each line of text corresponds to a &amp;#8220;step&amp;#8221;, which is defined in another file. Here&amp;#8217;s an example from the standard &lt;code&gt;webrat_steps.rb&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Then&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;see&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;([^&lt;span class="escape"&gt;\&amp;quot;&lt;/span&gt;]*)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;contain&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cucumber encourages you to think at a very high level, and to specify how different users will actually use your software. It&amp;#8217;s particularly helpful if you need to communicate between programmers and end-users.&lt;/p&gt;

&lt;h3&gt;My experiences with RSpec and Cucumber&lt;/h3&gt;

&lt;p&gt;I&amp;#8217;ve been using RSpec on and off for a couple of years now, and Cucumber since late last year. Initially, I found both tools fascinating, but also a bit frustrating. Both RSpec and Cucumber have very strong opinions about how you should write software. Now, I found those opinions very interesting, and I was quite happy to be influenced by the assumptions built into the tools. But every now and then, I would need to do something that the authors of RSpec and Cucumber hadn&amp;#8217;t anticipated, and I would inevitably wind up struggling to make things work.&lt;/p&gt;

&lt;p&gt;But recent versions of RSpec and Cucumber are richer and more flexible. They cover more important cases straight out of the box, and they&amp;#8217;re easier to customize. So I can finally recommend both tools for real-world projects: They&amp;#8217;ll still guide your thinking, but they should give you enough flexibility to handle the corner-cases.&lt;/p&gt;

&lt;h3&gt;The RSpec (and Cucumber) book&lt;/h3&gt;

&lt;p&gt;Unfortunately, the documentation for RSpec and Cucumber is scattered around the web, and there aren&amp;#8217;t enough online guides showing the best way to solve common problems.&lt;/p&gt;

&lt;p&gt;But the Pragmatic Press is working on &lt;a href="http://www.pragprog.com/titles/achbd/the-rspec-book"&gt;The RSpec Book&lt;/a&gt;, which contains a large section on Cucumber, and a walkthrough of a typical development session using Cucumber and RSpec.&lt;/p&gt;

&lt;p&gt;Currently, the RSpec book is available as a &amp;#8220;beta book&amp;#8221;. This is a downloadable, DRM-free PDF, with periodic updates throughout the publishing process.  Right now, between one-third and one-half of the chapters have been roughed in, and the book is already very useful.&lt;/p&gt;

&lt;p&gt;So if you&amp;#8217;re curious about &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; and &lt;a href="http://rspec.info/"&gt;Cucumber&lt;/a&gt;, have a look around the two web sites, and maybe watch some of the screencasts. If you decide to investigate further, pick up the beta book and dive in.&lt;/p&gt;</description>
      <pubDate>Thu, 30 Apr 2009 15:07:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:6e7a670a-6d09-430d-b788-da8135f1d8e2</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2009/04/30/rspec-cucumber-book-recommendation</link>
      <category>Ruby</category>
      <category>RSpec</category>
      <category>Cucumber</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/610</trackback:ping>
    </item>
    <item>
      <title>Remote root holes reported as &amp;quot;denial of service&amp;quot;</title>
      <description>&lt;p&gt;Via &lt;a href="http://lwn.net/Articles/330866/"&gt;LWN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re a Linux system administrator, you shouldn&amp;#8217;t put your faith in security advisories. The &lt;a href="http://kernelbof.blogspot.com/2009/04/kernel-memory-corruptions-are-not-just.html"&gt;kernelbof&lt;/a&gt; blog accuses Linux distributors of being too quick to label security bugs as &amp;#8220;denial of service&amp;#8221; attacks:&lt;/p&gt;

&lt;blockquote&gt;
I&amp;#8217;m wondering why kernel developers (or vendors?) continue to claim that kernel memory corruption are just Denial of Service. Most of the times they _are_ exploitable.
&lt;/blockquote&gt;

&lt;p&gt;As an example, the author quotes &lt;a href="http://www.ubuntu.com/usn/usn-751-1"&gt;Ubuntu Security Notice 751&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;The SCTP stack did not correctly validate FORWARD-TSN packets. A remote attacker could send specially crafted SCTP traffic causing a system crash, &lt;strong&gt;leading to a denial of service.&lt;/strong&gt;&lt;/blockquote&gt;

&lt;p&gt;(Emphasis added.)&lt;/p&gt;

&lt;p&gt;The author claims, however, to have created an exploit for this bug. He says his exploit allows a remote attacker to gain root access, often on the first attempt. If this is true, it would give him a quick way to gain control over any Linux system which has a process listening to an SCTP socket.&lt;/p&gt;

&lt;p&gt;Ubuntu&amp;#8217;s security team is not doing system administrators any favors by labeling memory corruption as &amp;#8220;denial of service&amp;#8221; attacks. If you can corrupt memory, there are some terrifyingly clever ways to run code. And marking memory as non-executable won&amp;#8217;t necessarily protect you.&lt;/p&gt;

&lt;p&gt;If you administer a Linux system, you should probably aim to patch alleged &amp;#8220;denial of service&amp;#8221; bugs as quickly as you can.&lt;/p&gt;</description>
      <pubDate>Thu, 30 Apr 2009 12:57:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:c25e2eee-9864-43d8-8b0b-6b0c0a4af6b1</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2009/04/30/remote-root-holes-reported-as-denial-of-service</link>
      <category>Linux</category>
      <category>Security</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/609</trackback:ping>
    </item>
    <item>
      <title>Installing TortoiseGit</title>
      <description>&lt;p&gt;On December 12th, Frank Li released &lt;a href="http://code.google.com/p/tortoisegit/"&gt;TortoiseGit&lt;/a&gt; 0.1. When we downloaded this initial release at work, we were underwhelmed:&lt;/p&gt;

&lt;div style="margin-left: 1em; margin-bottom: 1em"&gt;
&lt;table width="100%"&gt;
&lt;colgroup&gt;
&lt;col width="25%" /&gt;
&lt;col width="75%" /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git log&lt;/td&gt;&lt;td&gt;OK, but not as good as gitk&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git commit&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Broken&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;On January 4th, however, Frank Li released TortoiseGit 0.2. He&amp;#8217;d been extremely busy:&lt;/p&gt;

&lt;div style="margin-left: 1em; margin-bottom: 1em"&gt;
&lt;table width="100%" valign="top"&gt;
&lt;colgroup&gt;
&lt;col width="25%" /&gt;
&lt;col width="75%" /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git log&lt;/td&gt;&lt;td&gt;OK, but not as good as gitk&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git commit&lt;/td&gt;&lt;td&gt;OK (except for &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;rm&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git add&lt;/td&gt;&lt;td&gt;&lt;b&gt;Broken&lt;/b&gt; (see &lt;a href="http://code.google.com/p/tortoisegit/issues/detail?id=6"&gt;Bug 6&lt;/a&gt; for workaround)&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git rm&lt;/td&gt;&lt;td&gt;&lt;b&gt;Broken&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git status&lt;/td&gt;&lt;td&gt;OK&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git pull&lt;/td&gt;&lt;td&gt;OK&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git push&lt;/td&gt;&lt;td&gt;OK&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;SSH&lt;/td&gt;&lt;td&gt;OK (tested with PuTTY)&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;git clone&lt;/td&gt;&lt;td&gt;Always clones to home directory (see &lt;a href="http://code.google.com/p/tortoisegit/issues/detail?id=8"&gt;Bug 8&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;Clean merge&lt;/td&gt;&lt;td&gt;OK&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;Conflicted merge&lt;/td&gt;&lt;td&gt;&lt;b&gt;Manual&lt;/b&gt;, as with command-line tool&lt;/td&gt;&lt;/tr&gt;
&lt;tr valign="top"&gt;&lt;td&gt;Submodules&lt;/td&gt;&lt;td&gt;&lt;b&gt;No support&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Basically, TortoiseGit 0.2 is &lt;i&gt;almost&lt;/i&gt; usable, and the project is proceeding at a breakneck pace. If you have Windows users that you want to migrate to Git&amp;#8212;and who don&amp;#8217;t want to use the command-line tool&amp;#8212;it&amp;#8217;s worth a look.&lt;/p&gt;

&lt;p&gt;Installation instructions follow.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2009/01/11/installing-tortoisegit"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sun, 11 Jan 2009 09:55:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:544548e2-fac5-44f3-bb47-8d1b112c9808</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2009/01/11/installing-tortoisegit</link>
      <category>Git</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/597</trackback:ping>
    </item>
    <item>
      <title>Ubiquitous Hoogle</title>
      <description>&lt;p&gt;&lt;a href="https://wiki.mozilla.org/Labs/Ubiquity/Ubiquity_0.1_User_Tutorial"&gt;Ubiquity&lt;/a&gt; is an experimental Firefox plugin. It&amp;#8217;s a &amp;#8220;graphical command line&amp;#8221; similar to &lt;a href="http://en.wikipedia.org/wiki/Quicksilver_" title="software"&gt;QuickSilver&lt;/a&gt; on the Macintosh.&lt;/p&gt;

&lt;p&gt;You can easily add your own commands to Ubiquity. The following article shows how to create a &lt;a href="http://www.haskell.org/hoogle/"&gt;Hoogle&lt;/a&gt; search command that looks up &lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt; functions by name or by type signature.&lt;/p&gt;

&lt;p&gt;&lt;img src="/files/ubiq-hoogle-putStr.png" width="534" height="407" alt="Searching for putStr" /&gt;&lt;/p&gt;

&lt;p&gt;You can press &lt;strong&gt;Return&lt;/strong&gt; or click on one the links in the preview.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2008/09/01/ubiquitous-hoogle"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 01 Sep 2008 10:33:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:9f156248-1302-4cdc-9755-3007955a2677</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2008/09/01/ubiquitous-hoogle</link>
      <category>Haskell</category>
      <category>JavaScript</category>
      <category>Firefox</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/581</trackback:ping>
    </item>
    <item>
      <title>Probability monads at Hac 07 II</title>
      <description>&lt;p&gt;From October 5-7, I&amp;#8217;ll be at the &lt;a href="http://www.haskell.org/haskellwiki/Hac_2007_II"&gt;Haskell Hackathon in Freiburg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll be working on probability monads, attempting to turn my &lt;a href="http://www.randomhacks.net/articles/2007/04/19/robot-localization-particle-system-monad"&gt;various blog articles&lt;/a&gt; into a real Haskell library.&lt;/p&gt;

&lt;p&gt;Some resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.randomhacks.net/darcs/probability/"&gt;Control.Monad.Probability source code&lt;/a&gt;: This is the as-yet-unreconstructed code from my blog posts.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.randomhacks.net/darcs/probability-monads/probability-monads.pdf"&gt;Draft paper on probability monads&lt;/a&gt;: This paper explains the theory, and it has terser implementations of some ideas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you were a peer reviewer, or gave me feedback on the paper, my humble thanks&amp;#8211;and apologies. I haven&amp;#8217;t had a chance to revise the paper yet, and so your feedback is not yet included.&lt;/p&gt;

&lt;p&gt;See you at the Hackathon!&lt;/p&gt;</description>
      <pubDate>Tue, 02 Oct 2007 07:50:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:1603ed79-bdc5-4bf1-aafd-33c8c29bb6de</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/10/02/probability-monads-at-hac-07-ii</link>
      <category>Haskell</category>
      <category>Math</category>
      <category>Monads</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/509</trackback:ping>
    </item>
    <item>
      <title>Freiburg in October: Scheme, Dylan, and probability monads</title>
      <description>&lt;p&gt;Good morning! I&amp;#8217;ll be in Freiburg for several events this October, including &lt;a href="http://cufp.galois.com/"&gt;CUFP&lt;/a&gt; and the &lt;a href="http://haskell.org/haskellwiki/Hac_2007_II"&gt;Haskell Hackathon&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Commercial Users of Functional Programming (CUFP)&lt;/h4&gt;

&lt;p&gt;On October 4th, I&amp;#8217;ll be speaking at &lt;a href="http://cufp.galois.com/"&gt;CUFP &amp;rsquo;07&lt;/a&gt;, describing the use of Scheme in a real-world multimedia engine. Some likely topics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How we switched to Scheme (and why refactoring is your friend).&lt;/li&gt;
&lt;li&gt;How our artists learned to program in Scheme (it&amp;#8217;s all about the tools).&lt;/li&gt;
&lt;li&gt;The tension between functional programming and objects: Can we have both?&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Dylan Beer Night&lt;/h4&gt;

&lt;p&gt;Once upon a time, I dreamt of &lt;a href="http://www.cs.dartmouth.edu/reports/abstracts/TR2001-404/"&gt;generic functions&lt;/a&gt; and built RPMs for &lt;a href="http://web.archive.org/web/19990125095755/http://www.gwydiondylan.org/"&gt;Gwydion Dylan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some current and former Dylan hackers are hoping to meet in Freiburg, most likely on October 4th. If you&amp;#8217;re at ICFP or one of the workshops, we&amp;#8217;d love to hear from you.&lt;/p&gt;

&lt;h4&gt;Haskell Hackathon&lt;/h4&gt;

&lt;p&gt;I&amp;#8217;ll be at the &lt;a href="http://haskell.org/haskellwiki/Hac_2007_II"&gt;Haskell Hackathon&lt;/a&gt; from Friday to Sunday.&lt;/p&gt;

&lt;p&gt;Perhaps it&amp;#8217;s time to whip &lt;a href="http://www.randomhacks.net/darcs/probability/"&gt;Control.Monad.Probability&lt;/a&gt; into shape?&lt;/p&gt;</description>
      <pubDate>Tue, 18 Sep 2007 12:36:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:b660e303-82af-41f0-8576-ad58b8fb8cc0</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/09/18/freiburg-in-october</link>
      <category>Scheme</category>
      <category>Dylan</category>
      <category>Haskell</category>
      <category>Monads</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/506</trackback:ping>
    </item>
    <item>
      <title>September 8th, 2007</title>
      <description>&lt;p style="text-align: center"&gt;&lt;img src="http://www.randomhacks.net/files/wedding.jpg" alt="Bride and groom, with flowers." /&gt;&lt;/p&gt;

&lt;p style="text-align: center"&gt;Just married! Our thanks and love to everyone,&lt;br /&gt; for everything.&lt;/p&gt;</description>
      <pubDate>Tue, 18 Sep 2007 11:15:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:63125daf-10c6-4511-91b3-6cdf8d595458</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/09/18/just-married</link>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/504</trackback:ping>
    </item>
    <item>
      <title>Ruby-style metaprogramming in JavaScript (plus a port of RSpec)</title>
      <description>&lt;p&gt;Programming in Ruby makes me happy.  It&amp;#8217;s a lovable language, with a
pleasantly quirky syntax and lots of expressive power.&lt;/p&gt;

&lt;p&gt;Programming in JavaScript, on the other hand, frustrates me to no end.
JavaScript &lt;i&gt;could&lt;/i&gt; be a reasonable language, but it has all sorts of
ugly corner cases, and it forces me to roll everything from scratch.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been trying to make JavaScript a bit more like Ruby.  In particular, I
want to support Ruby-style metaprogramming in JavaScript.  This would make it possible to port over many advanced Ruby libraries.&lt;/p&gt;

&lt;p&gt;You can
check out the &lt;a href="http://www.randomhacks.net/svn/planetary/tags/0.1.0/spec_checker.html"&gt;interactive specification&lt;/a&gt;, or look at some examples
below.  If the &lt;a href="http://www.randomhacks.net/svn/planetary/tags/0.1.0/spec_checker.html"&gt;specification&lt;/a&gt; gives you any errors, please post them in the comment
thread, and let me know what browser you&amp;#8217;re running!&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2007/07/01/ruby-metaprogramming-javascript-rspec-bdd"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sun, 01 Jul 2007 19:00:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:421e0747-a145-4fc3-b0f1-8a5323eaea01</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/07/01/ruby-metaprogramming-javascript-rspec-bdd</link>
      <category>Ruby</category>
      <category>JavaScript</category>
      <category>Macros</category>
      <category>Planetary</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/472</trackback:ping>
    </item>
  </channel>
</rss>
