<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DEcMQ38_eSp7ImA9WxBUGEk.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112</id><updated>2010-03-05T21:28:02.141-06:00</updated><title>Techspeak</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://techspeak.plainlystated.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/plainlystated/xtwL" /><feedburner:info uri="plainlystated/xtwl" /><entry gd:etag="W/&quot;CkANRnY7cCp7ImA9WxBUGEw.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-4020985151610674121</id><published>2010-03-03T23:24:00.007-06:00</published><updated>2010-03-05T11:39:57.808-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-05T11:39:57.808-06:00</app:edited><title>Drop-Dead Simple Authentication for Microapps</title><content type="html">For &lt;a href="http://www.inspectinator.com"&gt;Inspectinator&lt;/a&gt; (a sinatra microapp), I needed a database-less authentication solution that was as lightweight as possible, but with a reasonable amount of security and maintainability. I came up with something that suits this purpose well, and &lt;a href="http://gist.github.com/321413"&gt;I'm sharing it&lt;/a&gt; in case anyone is looking for something similar. I call it EasyAuth.&lt;br /&gt;
&lt;br /&gt;
To use EasyAuth to authenticate your sinatra app, you first need to generate hashed passwords for each user you want to allow into your system. You can do this easily in IRB:&lt;br /&gt;
&lt;div class="vim_block"&gt;$ irb -r lib/easy_auth/easy_auth.rb&lt;br /&gt;
irb(main):001:0&amp;gt; EasyAuth.hash_password(&amp;quot;foobar&amp;quot;)&lt;br /&gt;
=&amp;gt; &amp;quot;8843d7f92416211de9ebb963ff4ce28125932878&amp;quot;&lt;br /&gt;
&lt;/div&gt;This should be stored in your easy_auth.rb, in the AUTHORIZED_USERS hash.&lt;br /&gt;
&lt;br /&gt;
Next, you mix-in EasyAuth, and in your password-protected route you do something like:&lt;br /&gt;
&lt;div class="vim_block"&gt;&lt;span class="PreProc"&gt;include&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;EasyAuth&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
get &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;/admin&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;do&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;if_auth &lt;span class="Statement"&gt;do&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;erb :&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;admin/index&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
post &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;/admin&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;do&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;if_auth(params[&lt;span class="Constant"&gt;:login&lt;/span&gt;], params[&lt;span class="Constant"&gt;:password&lt;/span&gt;]) &lt;span class="Statement"&gt;do&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redirect &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;/admin&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
EasyAuth yields to the block if authentication is successful (either based on the passed-in credentials, or cookies). It defaults to rendering /admin/login if not already authenticated, so throw a username/password form on that page and you should be good to go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-4020985151610674121?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=gYO1b4mkUsI:ih2CM2xCpw8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=gYO1b4mkUsI:ih2CM2xCpw8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=gYO1b4mkUsI:ih2CM2xCpw8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/gYO1b4mkUsI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/4020985151610674121/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2010/03/drop-dead-simple-authentication-for.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4020985151610674121?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4020985151610674121?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/gYO1b4mkUsI/drop-dead-simple-authentication-for.html" title="Drop-Dead Simple Authentication for Microapps" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2010/03/drop-dead-simple-authentication-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUFR3czfyp7ImA9WxBVEkw.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-2445148335928503108</id><published>2010-02-14T16:30:00.001-06:00</published><updated>2010-02-15T01:16:56.987-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-15T01:16:56.987-06:00</app:edited><title>Drop-Dead Simple Token Generation -- Fixnum#to_s</title><content type="html">For &lt;a href="http://www.inspectinator.com/"&gt;Inspectinator&lt;/a&gt;, I needed a lightweight token generator to allow people to share their results. I &lt;a href="http://blog.logeek.fr/2009/7/2/creating-small-unique-tokens-in-ruby"&gt;found&lt;/a&gt; a great solution, and learned a cool ruby trick, too.&lt;br /&gt;
&lt;br /&gt;
The trick is in Fixnum (and Bignum), #to_s takes an optional argument: a number in (2..36). That number is the base it will print the number in (default is 10).&lt;br /&gt;
&lt;br /&gt;
So, for instance (from the ruby docs), to convert a number to binary:&lt;br /&gt;
&lt;div class="vim_block"&gt;&lt;span class="Number"&gt;12345654321&lt;/span&gt;.to_s(&lt;span class="Number"&gt;2&lt;/span&gt;)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Comment"&gt;#=&amp;gt; "1011011111110110111011110000110001"&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
For my token, I went with an 8-character, base 36 number, which gives me almost 3 trillion possible values (should be plenty). To get the 8 characters, I use rand(36**8). I don't do any checking on the length, so 8 is actually the max length (and 1 is the min).  In practice, though, the vast majority of tokens will be the target length. On my system, I generated 10,000,000 tokens, and 9,722,373 were 8 characters. I chose to accept that as "close enough" because 1) it doesn't really matter to me if tokens are shorter, and 2) I think the simplicity and elegance of this solution is worth a little uncertainty.&lt;br /&gt;
&lt;br /&gt;
Then, (since I'm using active record), it's just a matter of adding a before_create to set it up:&lt;br /&gt;
&lt;div class="vim_block"&gt;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;set_token&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;t = &lt;span class="Constant"&gt;nil&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;begin&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;t = rand(&lt;span class="Number"&gt;36&lt;/span&gt;**&lt;span class="Number"&gt;8&lt;/span&gt;).to_s(&lt;span class="Number"&gt;36&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;while&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;InspectString&lt;/span&gt;.find_by_token(t)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="Constant"&gt;self&lt;/span&gt;.token = t&lt;br /&gt;
&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-2445148335928503108?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=pc9rM296BSU:ymhkTzi54BQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=pc9rM296BSU:ymhkTzi54BQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=pc9rM296BSU:ymhkTzi54BQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/pc9rM296BSU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/2445148335928503108/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2010/02/drop-dead-simple-token-generation.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/2445148335928503108?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/2445148335928503108?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/pc9rM296BSU/drop-dead-simple-token-generation.html" title="Drop-Dead Simple Token Generation -- Fixnum#to_s" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2010/02/drop-dead-simple-token-generation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUIBQXc4fSp7ImA9WxBVEUU.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-8929848642935817995</id><published>2010-02-14T15:39:00.000-06:00</published><updated>2010-02-14T15:39:10.935-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-14T15:39:10.935-06:00</app:edited><title>Announcing Inspectinator</title><content type="html">I've been wanting to experiment with sinatra for a while, so I popped something off my things-to-do-someday list and put together &lt;a href="http://www.inspectinator.com/"&gt;Inspectinator&lt;/a&gt;.&amp;nbsp; It's aim is pretty straight-forward: parse standard ruby #inspect strings into a more palatable form.&amp;nbsp; It parses a string into a system of nested objects, and displays it as a tree.&amp;nbsp; Some simple jQuery let's you drill down to the level of detail you want.&amp;nbsp; You can also link to your results (like pastie for inspects).&lt;br /&gt;
&lt;br /&gt;
Obviously #inspect output can be overridden to anything, but as long as it's along the lines of standard ruby or rails forms, it should be parseable.&amp;nbsp; If you find something that won't parse (or parses wrong), hit the link at the top ("Parse Error?") and I'll have a look.&lt;br /&gt;
&lt;br /&gt;
It's still in development, and I'm definitely open to thoughts/suggestions about improvements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-8929848642935817995?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=7qo7fiKGwbo:XAqeNbxWBdY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=7qo7fiKGwbo:XAqeNbxWBdY:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=7qo7fiKGwbo:XAqeNbxWBdY:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/7qo7fiKGwbo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/8929848642935817995/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2010/02/announcing-inspectinator.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/8929848642935817995?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/8929848642935817995?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/7qo7fiKGwbo/announcing-inspectinator.html" title="Announcing Inspectinator" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2010/02/announcing-inspectinator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUGRn44eyp7ImA9WxNSFkw.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-4148738156761412504</id><published>2009-08-30T00:27:00.001-05:00</published><updated>2009-08-30T01:03:47.033-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-30T01:03:47.033-05:00</app:edited><title>Ruby Hoedown '09</title><content type="html">This weekend I was in Nashville, TN for &lt;a href="http://rubyhoedown.com/"&gt;Ruby Hoedown 2009&lt;/a&gt;.&amp;nbsp; There were some great talks -- my favorites were Ben Mabey's Cucumber &lt;a href="http://www.benmabey.com/2009/08/28/writing-software-not-code-with-cucumber-slides-from-ruby-hoedown/"&gt;talk&lt;/a&gt;, Luigi Montanez's &lt;a href="http://luigimontanez.com/2009/on-being-a-civic-coder"&gt;talk&lt;/a&gt; on using public data APIs for civic coding, and Jim Weirich's excellent (and impromtu) &lt;a href="http://github.com/jimweirich/presentation_source_control/tree/master"&gt;talk&lt;/a&gt; on Git's internals.&lt;br /&gt;
&lt;br /&gt;
After my recent difficulties with getting Rhodes working for mobile development, I was really excited about Leon Gersing's talk about Appcelerator Titanium, but I missed all but the last five minutes of it because the schedule was changed for some reason (I was skipping what I *thought* was something else). =/&amp;nbsp; Hopefully he'll post some slides.&lt;br /&gt;
&lt;br /&gt;
The resort where the event was held was &lt;a href="http://forthright.plainlystated.com/2009/08/gaylord-opryland-resort.html"&gt;horrid&lt;/a&gt;, but the conference was a lot of fun.&amp;nbsp; Hope they continue this next year.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-4148738156761412504?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Jlbqi7nejJo:DmS-r6YkSzE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Jlbqi7nejJo:DmS-r6YkSzE:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=Jlbqi7nejJo:DmS-r6YkSzE:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/Jlbqi7nejJo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/4148738156761412504/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/08/ruby-hoedown-09.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4148738156761412504?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4148738156761412504?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/Jlbqi7nejJo/ruby-hoedown-09.html" title="Ruby Hoedown '09" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/08/ruby-hoedown-09.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMERng6fyp7ImA9WxNSEUo.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-713580495563551030</id><published>2009-08-24T21:50:00.004-05:00</published><updated>2009-08-24T22:20:07.617-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-24T22:20:07.617-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="erlang ruby" /><title>Erlang &amp; Ruby -- Ring Network</title><content type="html">As part of my Erlang self-education, I'm doing a selection of sample problems (from the "Programming Erlang" book) in both Erlang and my language of choice: Ruby. The idea is to explore the differences between these very different languages.&lt;br /&gt;&lt;br /&gt;Today's problem is to write a ring network benchmark.  Given a network of N nodes, where each node is pointing to the next in line (or back to the first), each node should forward a received message along, until it has gone around the ring M times (so that a total of N * M messages are sent).&lt;br /&gt;&lt;br /&gt;To start with, I came up with an Erlang module to spawn a set of processes, and pass along a message record. It was pretty ugly at first, but with a little refactoring it turned out alright:&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Keyword"&gt;-module&lt;/span&gt;(&lt;span class="Normal"&gt;ring_network&lt;/span&gt;).&lt;br /&gt;&lt;span class="Keyword"&gt;-export&lt;/span&gt;(&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Normal"&gt;start_ring&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Number"&gt;1&lt;/span&gt;, &lt;span class="Normal"&gt;start_message&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Number"&gt;3&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span class="Keyword"&gt;-record&lt;/span&gt;(&lt;span class="Normal"&gt;message&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Normal"&gt;loops_remaining&lt;/span&gt;&lt;span class="Statement"&gt;=&lt;/span&gt;&lt;span class="Number"&gt;300&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;times_sent&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;0&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;runtime&lt;/span&gt;, &lt;span class="Normal"&gt;wall_clock&lt;/span&gt;, &lt;span class="Normal"&gt;owner&lt;/span&gt;, &lt;span class="Normal"&gt;note&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;start_ring(&lt;span class="Identifier"&gt;N&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Keyword"&gt;spawn&lt;/span&gt;(&lt;span class="Keyword"&gt;fun&lt;/span&gt;() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;FirstPid&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;start_ring(&lt;span class="Identifier"&gt;N&lt;/span&gt;&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Number"&gt;1&lt;/span&gt;, &lt;span class="Keyword"&gt;self&lt;/span&gt;()),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;io&lt;/span&gt;:format(&lt;span class="String"&gt;&amp;quot;Starting node &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;(&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;) pointing to &lt;/span&gt;&lt;span class="Special"&gt;~p~n&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Identifier"&gt;N&lt;/span&gt;, &lt;span class="Keyword"&gt;self&lt;/span&gt;(), &lt;span class="Identifier"&gt;FirstPid&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;loop(&lt;span class="Identifier"&gt;N&lt;/span&gt;, &lt;span class="Identifier"&gt;FirstPid&lt;/span&gt;) &lt;span class="Statement"&gt;end&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;start_ring(&lt;span class="Identifier"&gt;N&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;Pid&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;start_node(&lt;span class="Identifier"&gt;N&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;if&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;N&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;1&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&amp;nbsp;start_ring(&lt;span class="Identifier"&gt;N&lt;/span&gt;&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Number"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;Pid&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Constant"&gt;true&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Pid&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;start_node(&lt;span class="Identifier"&gt;Id&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Keyword"&gt;spawn&lt;/span&gt;(&lt;span class="Keyword"&gt;fun&lt;/span&gt;() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;io&lt;/span&gt;:format(&lt;span class="String"&gt;&amp;quot;Starting node &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;(&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;) pointing to &lt;/span&gt;&lt;span class="Special"&gt;~p~n&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Identifier"&gt;Id&lt;/span&gt;, &lt;span class="Keyword"&gt;self&lt;/span&gt;(), &lt;span class="Identifier"&gt;Next&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;loop(&lt;span class="Identifier"&gt;Id&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;start_message(&lt;span class="Identifier"&gt;Pid&lt;/span&gt;, &lt;span class="Identifier"&gt;Msg&lt;/span&gt;, &lt;span class="Identifier"&gt;N&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Identifier"&gt;Runtime&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;statistics&lt;/span&gt;(&lt;span class="Normal"&gt;runtime&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Identifier"&gt;WallClock&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;statistics&lt;/span&gt;(&lt;span class="Normal"&gt;wall_clock&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;Pid&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;!&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;#message&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;loops_remaining&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;N&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;runtime&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Runtime&lt;/span&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;wall_clock&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;WallClock&lt;/span&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;owner&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Pid&lt;/span&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;note&lt;/span&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;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Msg&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;loop(&lt;span class="Identifier"&gt;Id&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Keyword"&gt;receive&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;case&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;owner&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;==&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;self&lt;/span&gt;() &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Constant"&gt;false&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;Next&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;!&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&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;&lt;span class="Normal"&gt;times_sent&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;times_sent&lt;/span&gt;&lt;span class="Statement"&gt;+&lt;/span&gt;&lt;span class="Number"&gt;1&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;loop(&lt;span class="Identifier"&gt;Id&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Constant"&gt;true&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;case&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;loops_remaining&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;==&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;0&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;of&lt;/span&gt;&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;&lt;span class="Constant"&gt;false&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&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;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;Next&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;!&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;times_sent&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;times_sent&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;+&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;1&lt;/span&gt;,&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;loops_remaining&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;loops_remaining&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;1&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&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;&amp;nbsp;&amp;nbsp;loop(&lt;span class="Identifier"&gt;Id&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;);&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;&lt;span class="Constant"&gt;true&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&amp;nbsp;&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;&amp;nbsp;&amp;nbsp;print_totals(&lt;span class="Identifier"&gt;Message&lt;/span&gt;),&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;&amp;nbsp;&amp;nbsp;loop(&lt;span class="Identifier"&gt;Id&lt;/span&gt;, &lt;span class="Identifier"&gt;Next&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;print_totals(&lt;span class="Identifier"&gt;Message&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Identifier"&gt;R2&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;statistics&lt;/span&gt;(&lt;span class="Normal"&gt;runtime&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Identifier"&gt;W2&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;statistics&lt;/span&gt;(&lt;span class="Normal"&gt;wall_clock&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;U1&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;(&lt;span class="Identifier"&gt;R2&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;runtime&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;U2&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;(&lt;span class="Identifier"&gt;W2&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;wall_clock&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;io&lt;/span&gt;:format(&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;~n&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;io&lt;/span&gt;:format(&lt;span class="String"&gt;&amp;quot;Sent '&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;' &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;times in..&lt;/span&gt;&lt;span class="Special"&gt;~n&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;note&lt;/span&gt;, &lt;span class="Identifier"&gt;Message&lt;/span&gt;&lt;span class="Type"&gt;#message&lt;/span&gt;.&lt;span class="Normal"&gt;times_sent&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;io&lt;/span&gt;:format(&lt;span class="String"&gt;&amp;quot;&amp;nbsp;&amp;nbsp;Runtime: &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;milliseconds&lt;/span&gt;&lt;span class="Special"&gt;~n&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Identifier"&gt;U1&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Normal"&gt;io&lt;/span&gt;:format(&lt;span class="String"&gt;&amp;quot;&amp;nbsp;&amp;nbsp;WallClock: &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;milliseconds&lt;/span&gt;&lt;span class="Special"&gt;~n&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Identifier"&gt;U2&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;).&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next I applied the same pattern in ruby. I created a Node class, told it where the next node was, and had it forward messages along the proper number of times:&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;Node&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;attr_accessor&lt;/span&gt;&amp;nbsp;&lt;span class="Constant"&gt;:next_node&lt;/span&gt;, &lt;span class="Constant"&gt;:number&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;initialize&lt;/span&gt;(number, next_node = &lt;span class="Constant"&gt;nil&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;@number&lt;/span&gt;&amp;nbsp;= number&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;@next_node&lt;/span&gt;&amp;nbsp;= next_node&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Constant"&gt;self&lt;/span&gt;.&lt;span class="Function"&gt;ring_network&lt;/span&gt;(node_count)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nodes = &lt;span class="Type"&gt;Array&lt;/span&gt;.new(node_count)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nodes[&lt;span class="Number"&gt;0&lt;/span&gt;] = &lt;span class="Type"&gt;Node&lt;/span&gt;.new(&lt;span class="Number"&gt;1&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(&lt;span class="Number"&gt;1&lt;/span&gt;..node_count-&lt;span class="Number"&gt;1&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt;&amp;nbsp;|&lt;span class="Identifier"&gt;i&lt;/span&gt;|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nodes[i] = &lt;span class="Type"&gt;Node&lt;/span&gt;.new(i+&lt;span class="Number"&gt;1&lt;/span&gt;, nodes[i-&lt;span class="Number"&gt;1&lt;/span&gt;])&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nodes[&lt;span class="Number"&gt;0&lt;/span&gt;].next_node = nodes[-&lt;span class="Number"&gt;1&lt;/span&gt;]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nodes[-&lt;span class="Number"&gt;1&lt;/span&gt;]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;gets_message&lt;/span&gt;(msg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;if&lt;/span&gt;&amp;nbsp;msg.owner == &lt;span class="Constant"&gt;self&lt;/span&gt;.object_id&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;if&lt;/span&gt;&amp;nbsp;(msg.passes_remaining-=&lt;span class="Number"&gt;1&lt;/span&gt;) == &lt;span class="Number"&gt;0&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg.print_totals&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg.owner = &lt;span class="Constant"&gt;self&lt;/span&gt;.object_id &lt;span class="Statement"&gt;if&lt;/span&gt;&amp;nbsp;msg.owner.nil?&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg.total_passes += &lt;span class="Number"&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_node.gets_message(msg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;Message&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;attr_accessor&lt;/span&gt;&amp;nbsp;&lt;span class="Constant"&gt;:runtime&lt;/span&gt;, &lt;span class="Constant"&gt;:wallclock&lt;/span&gt;, &lt;span class="Constant"&gt;:note&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Constant"&gt;:passes_remaining&lt;/span&gt;, &lt;span class="Constant"&gt;:owner&lt;/span&gt;, &lt;span class="Constant"&gt;:start_time&lt;/span&gt;, &lt;span class="Constant"&gt;:total_passes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;initialize&lt;/span&gt;(note, passes_remaining = &lt;span class="Number"&gt;300&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;@total_passes&lt;/span&gt;&amp;nbsp;= &lt;span class="Number"&gt;0&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;@start_time&lt;/span&gt;&amp;nbsp;= &lt;span class="Type"&gt;Time&lt;/span&gt;.now&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;@note&lt;/span&gt;&amp;nbsp;= note&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;@passes_remaining&lt;/span&gt;&amp;nbsp;= passes_remaining&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;print_totals&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;puts&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;puts &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="String"&gt;Sent &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;total_passes&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;messages in...&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;puts &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;&amp;nbsp;WallClock: &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;(&lt;span class="Type"&gt;Time&lt;/span&gt;.now - &lt;span class="Identifier"&gt;@start_time&lt;/span&gt;) * &lt;span class="Number"&gt;1000&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="String"&gt;&amp;nbsp;milliseconds&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The first impression is just what you'd expect: Ruby is easier to read, and erlang is *much* faster:&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Number"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Pid&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;ring_network&lt;/span&gt;:start_ring(&lt;span class="Number"&gt;10&lt;/span&gt;).&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;10&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.59&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.68&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;9&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.60&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.59&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;8&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.61&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.60&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;7&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.62&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.61&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;6&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.63&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.62&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;5&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.64&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.63&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;4&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.65&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.64&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;3&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.66&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.65&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;2&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.67&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.66&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Starting&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;node&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;1&lt;/span&gt;&amp;nbsp;(&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.68&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="Normal"&gt;pointing&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.67&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.59&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Number"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;ring_network&lt;/span&gt;:start_message(&lt;span class="Identifier"&gt;Pid&lt;/span&gt;, &lt;span class="Normal"&gt;hello_world&lt;/span&gt;, &lt;span class="Number"&gt;300&lt;/span&gt;).&lt;br /&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Normal"&gt;message&lt;/span&gt;,&lt;span class="Number"&gt;300&lt;/span&gt;,&lt;span class="Number"&gt;0&lt;/span&gt;,&lt;span class="Number"&gt;270&lt;/span&gt;,&lt;span class="Number"&gt;298496&lt;/span&gt;,&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.59&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;,&lt;span class="Normal"&gt;hello_world&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;span class="Identifier"&gt;Sent&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;'hello_world'&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;3000&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;times&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;in&lt;/span&gt;..&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;Runtime&lt;/span&gt;: &lt;span class="Number"&gt;0&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;milliseconds&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;WallClock&lt;/span&gt;: &lt;span class="Number"&gt;3&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;milliseconds&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Versus...&lt;br /&gt;&lt;div class="vim_block"&gt;irb(main):&lt;span class="Number"&gt;001&lt;/span&gt;:&lt;span class="Number"&gt;0&lt;/span&gt;&amp;gt; node = &lt;span class="Type"&gt;Node&lt;/span&gt;.ring_network(&lt;span class="Number"&gt;10&lt;/span&gt;); msg = &lt;span class="Type"&gt;Message&lt;/span&gt;.new(&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;Hi!&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;, &lt;span class="Number"&gt;300&lt;/span&gt;); node.gets_message(msg)&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;Sent&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;3000&lt;/span&gt;&amp;nbsp;messages &lt;span class="Statement"&gt;in&lt;/span&gt;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Type"&gt;WallClock&lt;/span&gt;: &lt;span class="Number"&gt;79.336&lt;/span&gt;&amp;nbsp;milliseconds&lt;br /&gt;=&amp;gt; &lt;span class="Constant"&gt;nil&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The real difference comes out when you increase the numbers:&lt;br /&gt;(Erlang):&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Number"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;span class="Identifier"&gt;Pid&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;ring_network&lt;/span&gt;:start_ring(&lt;span class="Number"&gt;10000&lt;/span&gt;).&lt;br /&gt;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.33&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Number"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;ring_network&lt;/span&gt;:start_message(&lt;span class="Identifier"&gt;Pid&lt;/span&gt;, &lt;span class="Normal"&gt;hello_world&lt;/span&gt;, &lt;span class="Number"&gt;10000&lt;/span&gt;).&lt;br /&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Normal"&gt;message&lt;/span&gt;,&lt;span class="Number"&gt;10000&lt;/span&gt;,&lt;span class="Number"&gt;0&lt;/span&gt;,&lt;span class="Number"&gt;460&lt;/span&gt;,&lt;span class="Number"&gt;40488&lt;/span&gt;,&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Number"&gt;0.33&lt;/span&gt;.&lt;span class="Number"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;,&lt;span class="Normal"&gt;hello_world&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;span class="Identifier"&gt;Sent&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;'hello_world'&lt;/span&gt;&amp;nbsp;&lt;span class="Number"&gt;100000000&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;times&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;in&lt;/span&gt;..&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;Runtime&lt;/span&gt;: &lt;span class="Number"&gt;95350&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;milliseconds&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;WallClock&lt;/span&gt;: &lt;span class="Number"&gt;157455&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;milliseconds&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(Ruby):&lt;br /&gt;&lt;div class="vim_block"&gt;irb(main):&lt;span class="Number"&gt;002&lt;/span&gt;:&lt;span class="Number"&gt;0&lt;/span&gt;&amp;gt; node = &lt;span class="Type"&gt;Node&lt;/span&gt;.ring_network(&lt;span class="Number"&gt;100&lt;/span&gt;); msg = &lt;span class="Type"&gt;Message&lt;/span&gt;.new(&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;Hi!&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;, &lt;span class="Number"&gt;300&lt;/span&gt;); node.gets_message(msg)&lt;br /&gt;&lt;span class="Type"&gt;SystemStackError&lt;/span&gt;: stack level too deep&lt;br /&gt;&amp;nbsp;&amp;nbsp;from ./ring_network.rb:&lt;span class="Number"&gt;29&lt;/span&gt;&lt;span class="Constant"&gt;:in&lt;/span&gt;&amp;nbsp;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;gets_message&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;from ./ring_network.rb:&lt;span class="Number"&gt;29&lt;/span&gt;&lt;span class="Constant"&gt;:in&lt;/span&gt;&amp;nbsp;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;gets_message&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;from (irb):&lt;span class="Number"&gt;2&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;from :&lt;span class="Number"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In both cases, we're using recursion to wait for another message after processing one. In Erlang's case, though, it compiles tail recursion as a JUMP statement, which doesn't eat up stack space. Ruby doesn't do this, which is why I get a "stack too deep" when I up the number of loops. To get around this in ruby, I would have to move towards the Erlang module of forking off separate processes (not just separate instances), each listening for some interprocess communication.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-713580495563551030?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=PFJAVyfSULM:cFTSqMvN7Ro:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=PFJAVyfSULM:cFTSqMvN7Ro:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=PFJAVyfSULM:cFTSqMvN7Ro:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/PFJAVyfSULM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/713580495563551030/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/08/erlang-ruby-ring-network.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/713580495563551030?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/713580495563551030?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/PFJAVyfSULM/erlang-ruby-ring-network.html" title="Erlang &amp; Ruby -- Ring Network" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/08/erlang-ruby-ring-network.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIFRHc8eCp7ImA9WxNSEUo.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-2704506380058730618</id><published>2009-08-24T18:13:00.002-05:00</published><updated>2009-08-24T22:21:55.970-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-24T22:21:55.970-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="erlang ruby" /><title>Erlang &amp; Ruby</title><content type="html">I've been playing around with Erlang lately, and it's been quite a departure from the language I'm most comfortable with (and use everyday): Ruby.  As part of my exploration, I'm doing a variety of sample problems (from the "Programming Erlang" book, among other places) in both Ruby and Erlang, and comparing the different implementations I come up with.  Erlang and Ruby are meant to solve different types of problems, and the apples-to-oranges nature of the comparison should be kept in mind.  The goal is to improve both my Erlang and my Ruby.&lt;br /&gt;&lt;br /&gt;I'll be posting on this periodically under the tag &lt;a href="http://techspeak.plainlystated.com/search/label/erlang%20ruby"&gt;erlang_ruby&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-2704506380058730618?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=inClcqO70GU:h45C4BiDZH4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=inClcqO70GU:h45C4BiDZH4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=inClcqO70GU:h45C4BiDZH4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/inClcqO70GU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/2704506380058730618/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/08/erlang-ruby.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/2704506380058730618?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/2704506380058730618?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/inClcqO70GU/erlang-ruby.html" title="Erlang &amp; Ruby" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/08/erlang-ruby.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUDSH49cSp7ImA9WxNTF04.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-1318226031608504292</id><published>2009-08-19T22:01:00.000-05:00</published><updated>2009-08-19T22:01:19.069-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-19T22:01:19.069-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="pitfalls" /><title>ActiveRecord Callbacks Trigger on Clean Objects</title><content type="html">I came across this issue the other day at work, and I'm not really sure how I feel about it.  It doesn't necessarily seem right or wrong, but was definitely unintuitive for me...&lt;br /&gt;&lt;br /&gt;Since Rails 2.1, we have had dirty object checking, which prevents ActiveRecord from saving an object if if hasn't changed:&lt;br /&gt;&lt;div class="vim_block"&gt;&amp;gt;&amp;gt; person = Person.first&lt;br /&gt;&lt;span class="Type"&gt;&amp;nbsp;&amp;nbsp;Person Load&lt;/span&gt;&amp;nbsp;(0.9ms)&amp;nbsp;&amp;nbsp; &lt;span class="PreProc"&gt;SELECT * FROM &amp;quot;people&amp;quot; LIMIT 1&lt;/span&gt;&lt;br /&gt;=&amp;gt; #&amp;lt;Person id: 1, first_name: &amp;quot;Patrick&amp;quot;, last_name: &amp;quot;Schless&amp;quot;, nickname: nil, created_at: &amp;quot;2009-08-20 02:21:13&amp;quot;, updated_at: &amp;quot;2009-08-20 02:22:32&amp;quot;&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt; person.save&lt;br /&gt;=&amp;gt; true&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt; person.nickname = &amp;quot;nick&amp;quot;&lt;br /&gt;=&amp;gt; &amp;quot;nick&amp;quot;&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt; person.save&lt;br /&gt;&lt;span class="Type"&gt;&amp;nbsp;&amp;nbsp;Person Update&lt;/span&gt;&amp;nbsp;(20.6ms)&amp;nbsp;&amp;nbsp; &lt;span class="PreProc"&gt;UPDATE &amp;quot;people&amp;quot; SET &amp;quot;updated_at&amp;quot; = '2009-08-20 02:31:17', &amp;quot;nickname&amp;quot; = 'nick' WHERE &amp;quot;id&amp;quot; = 1&lt;/span&gt;&lt;br /&gt;=&amp;gt; true&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;That part is good, but what happens when you have a callback defined?&lt;br /&gt;&lt;div class="vim_block"&gt;&amp;gt;&amp;gt; Person.after_save { puts 'After save...' }&lt;br /&gt;=&amp;gt; [#&amp;lt;ActiveSupport::Callbacks::Callback:0xb7147898 @identifier=nil, @method=#&amp;lt;Proc:0xb71479d8@(irb):6&amp;gt;, @kind=:after_save, @options={}&amp;gt;]&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt; person.nickname = nil&lt;br /&gt;=&amp;gt; nil&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt; person.save&lt;br /&gt;&lt;span class="Type"&gt;&amp;nbsp;&amp;nbsp;Person Update&lt;/span&gt;&amp;nbsp;(2.4ms)&amp;nbsp;&amp;nbsp; &lt;span class="PreProc"&gt;UPDATE &amp;quot;people&amp;quot; SET &amp;quot;updated_at&amp;quot; = '2009-08-20 02:33:21', &amp;quot;nickname&amp;quot; = NULL WHERE &amp;quot;id&amp;quot; = 1&lt;/span&gt;&lt;br /&gt;After save...&lt;br /&gt;=&amp;gt; true&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt; person.save&lt;br /&gt;After save...&lt;br /&gt;=&amp;gt; true&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;As we see there, the callback gets triggered even if the save is short-circuited.&lt;br /&gt;&lt;br /&gt;In my trivial example, the behavior isn't terribly important either way.  However, if your callback is doing something relatively expensive it may be pointless (and wasteful) to do that on a clean object.  There are certainly situations where you would want it to always trigger, so I guess it's just one of those things that a developer ought to keep in the back of his mind when coding.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-1318226031608504292?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=jR6NA1apkcU:cGZTpyQGNx0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=jR6NA1apkcU:cGZTpyQGNx0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=jR6NA1apkcU:cGZTpyQGNx0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/jR6NA1apkcU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/1318226031608504292/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/03/activerecord-callbacks-trigger-on-clean.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/1318226031608504292?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/1318226031608504292?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/jR6NA1apkcU/activerecord-callbacks-trigger-on-clean.html" title="ActiveRecord Callbacks Trigger on Clean Objects" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/03/activerecord-callbacks-trigger-on-clean.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4DQnczeip7ImA9WxNTF08.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-4182179542261259531</id><published>2009-08-17T19:10:00.007-05:00</published><updated>2009-08-19T18:19:33.982-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-19T18:19:33.982-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vim" /><title>Vim -- :TOhtml &amp; Customization</title><content type="html">When I first started this blog, I was surprised (and disappointed) that Google's Blogger platform didn't have some nice built-in feature for code formatting and syntax highlighting. I experimented with a number of third-party solutions, but didn't find anything that I particularly liked, so my posts have had some ugly-looking code in them. Until now.&lt;br /&gt;&lt;br /&gt;...Well, until my &lt;a href="http://techspeak.plainlystated.com/2009/08/ruby-on-android-part-2.html"&gt;previous post&lt;/a&gt;, anyway.&lt;br /&gt;&lt;br /&gt;A &lt;a href="http://blog.oneeyedgringo.com/"&gt;then-coworker&lt;/a&gt; told me a while back about vim's :TOhtml feature, but it wasn't until last night that I actually checked it out.  As it turns out, it was just what I was looking for.  Out of the box, it's a little cumbersome for my purposes, but a little vim scripting helped a lot.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Default Behavior&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;To start, I set a few options in my .vimrc:&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Statement"&gt;let&lt;/span&gt; html_use_css &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Number"&gt;1&lt;/span&gt; &lt;span class="Comment"&gt;" Use stylesheet instead of inline style&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;let&lt;/span&gt; html_number_lines &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Number"&gt;0&lt;/span&gt; &lt;span class="Comment"&gt;" don't show line numbers&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;let&lt;/span&gt; html_no_pre &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Number"&gt;1&lt;/span&gt; &lt;span class="Comment"&gt;" don't wrap lines in &amp;lt;pre&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I also choose a vim color scheme I like (wombat).  You can look through examples of tons of schemes &lt;a href="http://code.google.com/p/vimcolorschemetest/"&gt;here&lt;/a&gt;.  (I spent a while trying to figure out why I couldn't set the color scheme (after I downloaded it to .vim/colors/), and the answer I found was that color schemes only work in gVim.)&lt;br /&gt;&lt;br /&gt;So, having set some options in my .vimrc, and chosen a colorscheme in gVim, calling :TOhtml on&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;Person&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;attr_accessor&lt;/span&gt;&amp;nbsp;&lt;span class="Constant"&gt;:age&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;speak&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="String"&gt;Hi!&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;say_age&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="String"&gt;I am this many: &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="String"&gt;|&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&amp;nbsp;* &lt;span class="Identifier"&gt;@age&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;gives:&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Comment"&gt;&amp;lt;!DOCTYPE HTML PUBLIC &amp;quot;-//W3C//DTD HTML 4.01 Transitional//EN&amp;quot; &amp;quot;&lt;a href="http://www.w3.org/TR/html4/loose.dtd"&gt;http://www.w3.org/TR/html4/loose.dtd&lt;/a&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;head&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;title&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Title"&gt;~/demo.rb.html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;title&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;meta&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;name&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Generator&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;content&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Vim/7.2&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;meta&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;http-equiv&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;content-type&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;content&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;text/html; charset=UTF-8&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;style&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;type&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Comment"&gt;&amp;lt;!--&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.Identifier&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#cae682&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.Type&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#cae682&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.Statement&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#8ac6f2&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.Constant&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#e5786d&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.Function&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#cae682&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.Special&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#e7f6da&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.String&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#95e454&lt;/span&gt;; &lt;span class="Type"&gt;font-style&lt;/span&gt;: &lt;span class="Type"&gt;italic&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;body&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#f6f3e8&lt;/span&gt;; &lt;span class="Type"&gt;background-color&lt;/span&gt;: &lt;span class="Constant"&gt;#242424&lt;/span&gt;; &lt;span class="Type"&gt;font-family&lt;/span&gt;: &lt;span class="Type"&gt;monospace&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;.PreProc&lt;/span&gt;&amp;nbsp;&lt;span class="Function"&gt;{&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;color&lt;/span&gt;: &lt;span class="Constant"&gt;#e5786d&lt;/span&gt;; &lt;span class="Function"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Comment"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;style&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;head&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;class&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Type&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;Person&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Statement&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;attr_accessor&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Constant&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;:age&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;def&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Function&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;speak&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;String&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;Hi!&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;end&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;def&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Function&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;say_age&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;String&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;I am this many: &lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;#{&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;'&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;String&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;|&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;'&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;* &lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Identifier&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;@age&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;}&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;end&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;end&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;br&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's pretty good.  If your goal was a stand-alone HTML file you'd be done, but for paste-ready output we need a little vim scripting help.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Altered Behavior&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Instead of wrapping the output in a full html page, I really just want it wrapped in a div.  I also want to strip out some "extra" (according to Blogger's HTML interpreter) line breaks, and pull out the CSS definitions (for later).  To accomplish this, I've put together a simple vim script, which defines a new method :DivHtml&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Statement"&gt;function&lt;/span&gt;! DivHtml&lt;span class="Statement"&gt;(&lt;/span&gt;line1, line2&lt;span class="Statement"&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;exec&lt;/span&gt;&amp;nbsp;a:line1&lt;span class="Statement"&gt;.&lt;/span&gt;&lt;span class="String"&gt;','&lt;/span&gt;&lt;span class="Statement"&gt;.&lt;/span&gt;a:line2&lt;span class="Statement"&gt;.&lt;/span&gt;&lt;span class="String"&gt;'TOhtml'&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Number"&gt;%&lt;/span&gt;g/&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;style/&lt;span class="Statement"&gt;normal&lt;/span&gt;&amp;nbsp;$dgg&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Number"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;s&lt;/span&gt;&lt;span class="Special"&gt;/&lt;/span&gt;&amp;lt;\/style&amp;gt;\n&amp;lt;\/head&amp;gt;\n&lt;span class="Special"&gt;//&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Number"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;s&lt;/span&gt;&lt;span class="Special"&gt;/&lt;/span&gt;.vim_block {&lt;span class="Special"&gt;/&lt;/span&gt;.vim_block {&lt;span class="Special"&gt;/&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Number"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;s&lt;/span&gt;&lt;span class="Special"&gt;/&lt;/span&gt;&amp;lt;body&lt;span class="Special"&gt;\(&lt;/span&gt;.*&lt;span class="Special"&gt;\)&lt;/span&gt;&amp;gt;\n&lt;span class="Special"&gt;/&lt;/span&gt;&amp;lt;div class=&amp;quot;vim_block&amp;quot;&lt;span class="Special"&gt;\1&lt;/span&gt;&amp;gt;&lt;span class="Special"&gt;/&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Number"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;s&lt;/span&gt;&lt;span class="Special"&gt;/&lt;/span&gt;&amp;lt;\/body&amp;gt;\n&amp;lt;\/html&amp;gt;/&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;\/div&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Number"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;s&lt;/span&gt;&lt;span class="Special"&gt;/&lt;/span&gt;&amp;lt;br&amp;gt;&lt;span class="Special"&gt;//&lt;/span&gt;&lt;span class="Special"&gt;g&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;set&lt;/span&gt;&amp;nbsp;&lt;span class="PreProc"&gt;nonu&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;endfunction&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;command&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="PreProc"&gt;range&lt;/span&gt;&lt;span class="Statement"&gt;=&lt;/span&gt;&lt;span class="Type"&gt;%&lt;/span&gt;&amp;nbsp;DivHtml&amp;nbsp;:&lt;span class="Statement"&gt;call&lt;/span&gt;&amp;nbsp;&lt;span class="Normal"&gt;DivHtml&lt;/span&gt;(&lt;span class="Special"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Special"&gt;line1&lt;/span&gt;&lt;span class="Special"&gt;&amp;gt;&lt;/span&gt;,&lt;span class="Special"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Special"&gt;line2&lt;/span&gt;&lt;span class="Special"&gt;&amp;gt;&lt;/span&gt;)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now, calling :DivHtml on the ruby code above gives code I can just cut &amp; paste into the 'Edit Html' Blogger window:&lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Comment"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="Comment"&gt;--&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.Identifier { color: #cae682; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.Type { color: #cae682; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.Statement { color: #8ac6f2; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.Constant { color: #e5786d; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.Function { color: #cae682; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.Special { color: #e7f6da; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.String { color: #95e454; font-style: italic; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.vim_block { color: #f6f3e8; background-color: #242424; font-family: monospace; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;.PreProc { color: #e5786d; }&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;--&lt;/span&gt;&lt;span class="Comment"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;div&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;vim_block&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;class&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Type&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;Person&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Statement&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;attr_accessor&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Constant&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;:age&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;def&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Function&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;speak&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;String&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;Hi!&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;end&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;def&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Function&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;say_age&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;String&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;I am this many: &lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;#{&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;'&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;String&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;|&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;'&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;nbsp;&lt;/span&gt;* &lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Identifier&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;@age&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;}&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;Special&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Special"&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;end&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;PreProc&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;end&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;div&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;(which renders as the ruby snippet I pasted above)&lt;br /&gt;&lt;br /&gt;The only part of the process that is still kinda annoying is that you have to copy/paste the CSS into your header or external CSS file.  Both :TOhtml and :DivHtml only output the CSS definitions for styles actually used in a snippet, so it's up to the user to check if all the definitions in a new snippet are already in your layout, or if you need to add them.  The alternative would be to use inline CSS (:help :TOhtml), but that's ugly.&lt;br /&gt;&lt;br /&gt;To finish things off, I gave the wrapping div the vim_block class, and gave that a background-color and border in my header, to make it look a little nicer. I also got rid of the "font-family: monospace" bit, because I thought it made the code hard to read.&lt;br /&gt;&lt;br /&gt;Other than manually checking the CSS, it's a very painless process to put code snippets on the blog, and I'm happy with the look and feel of them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-4182179542261259531?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=572ZZdx8Ip8:bXjEG7UhXyI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=572ZZdx8Ip8:bXjEG7UhXyI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=572ZZdx8Ip8:bXjEG7UhXyI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/572ZZdx8Ip8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/4182179542261259531/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/08/vim-tohtml-customization.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4182179542261259531?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4182179542261259531?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/572ZZdx8Ip8/vim-tohtml-customization.html" title="Vim -- :TOhtml &amp; Customization" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/08/vim-tohtml-customization.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYDRn4-fCp7ImA9WxNTFUg.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-7539490786591108134</id><published>2009-08-16T18:54:00.013-05:00</published><updated>2009-08-17T18:36:17.054-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-17T18:36:17.054-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile_ruby" /><title>Ruby on Android -- Part 2</title><content type="html">Continuing towards my goal of developing an application in ruby for my Android (see &lt;a href="http://techspeak.plainlystated.com/2009/07/ruby-on-android.html"&gt;part 1&lt;/a&gt;), I've been getting into &lt;a href="http://www.rhomobile.com/products/rhodes"&gt;Rhodes&lt;/a&gt;, which is an open-source project that aims to allow you to build native apps for a variety of mobile platforms, all from a lightweight ruby framework.  For Android, it uses xruby (not Jruby).&lt;br /&gt;&lt;br /&gt;I started with the documentation at the &lt;a href="http://wiki.rhomobile.com/index.php/Rhodes"&gt;Rhodes wiki&lt;/a&gt;, and checked out a &lt;a href="http://www.youtube.com/watch?v=T2pztOky_L0&amp;amp;feature=related"&gt;Google Talk&lt;/a&gt;.  I tried to duplicate the sample application in the video, but quickly starting hitting walls, which I have been trying to work through.  I haven't had a ton of success with it yet, but I'll document what success I have had.&lt;br /&gt;&lt;br /&gt;To start with, rhodes only seems to support Windows and Mac out of the box.  I have forked the rhodes project, to add in linux support, as well as try to fix whatever isn't working for me (which I'll get to later).  You can check out my forked rhodes my&lt;a href="http://github.com/patrickschless/rhodes/tree/master"&gt; github page&lt;/a&gt;. The easiest way to use the repo version (rather than the gems) is to set up an alias in your bash_profile such as: &lt;br /&gt;&lt;div class="vim_block"&gt;&lt;span class="Statement"&gt;alias &lt;/span&gt;&lt;span class="Identifier"&gt;rh&lt;/span&gt;&lt;span class="Statement"&gt;=&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="String"&gt;RUBYLIB=/home/rellik/repos/rhodes/rhodes/rhodes-build/lib:/home/rellik/repos/rhodes/rhodes/rhodes-framework/lib&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Prefacing any command with 'rh ' will then use the repo version of the Rhodes libraries.&lt;br /&gt;&lt;br /&gt;After generating an application with rhogen (found in the repo under rhodes-generator/bin/ or the rhodes-generator gem), the other platform-specific bit that you need to override is the build.yml file that gets generated for a new project.  Since I'm only concerned about Android at the moment, the only line I needed to change here was the last one, to point to the android.jar that came with my SDK.  For me, this amounts to:&lt;br /&gt;&lt;div class="vim_block"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Identifier"&gt;android&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&amp;nbsp;/home/rellik/Desktop/android&lt;span class="Statement"&gt;-&lt;/span&gt;sdk&lt;span class="Statement"&gt;-&lt;/span&gt;linux_x86&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Number"&gt;1.5&lt;/span&gt;_r3/platforms/android&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Number"&gt;1.5&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;With all this, I was still not having much luck with Rhodes.  I used 'rh rake run:android:app' to generate the apk and push it to the emulator.  I was getting an error about no space left on the virtual SD card, but I do like having the apk be signed as part of the rake task, so I usually just run:android:app (and let it fail), then install the application manually using 'adb install -r bin/target/Rhodes-debug.apk' (the emulator must already be running).&lt;br /&gt;&lt;br /&gt;Once the application is successfully installed on the emualator, you can slide the applications tray open and click on the Rhodes icon.  You'll see a 'Loading...' screen, then a blank screen.  For me, that's all there is.  I tried simplifying the index.erb file, and even taking out any logic, but still I get the same blank screen.  I renamed the non-dynamic index.erb to index.html, and that worked fine (I saw that page after 'Loading...'), so there seems to be something funky about rendering the ERB file.&lt;br /&gt;&lt;br /&gt;To debug this issue, I added a series of raises and debug statements to the rake task that builds the apk, and I discovered a few things.  First, the erb file gets converted to ruby, which contains the use of String#force_encoding (which is ruby 1.9).  I tried downloading and using ruby 1.9 for this, as well as just taking that line out of a generated erb file, but neither helped.&lt;br /&gt;&lt;br /&gt;Second, I left #force_encoding out, and I added "puts _erbout" as the last line of the generated erb file (bin/RhoBundle/apps/app/index_erb.rb), and then used the following to test if the generated java was any good, and indeed it was (but failed when I put force_encoding back in):&lt;br /&gt;&lt;br /&gt;&lt;div class="vim_block"&gt;$ java -cp /home/rellik/repos/rhodes/rhodes/rhodes-build/res/xruby-0.3.3.jar:bin/RhoBundle.jar xruby.apps.app.index_erb.main&lt;br /&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;div&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;class&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;toolbar&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;h1&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;id&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;pageTitle&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Title"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Contacter&lt;/span&gt;&lt;br /&gt;&lt;span class="Title"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;h1&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;div&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;ul&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;id&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;home&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;selected&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Type"&gt;title&lt;/span&gt;&lt;span class="Function"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;FirstApp&amp;quot;&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;span class="Function"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;li&lt;/span&gt;&lt;span class="Function"&gt;&amp;gt;&lt;/span&gt;Hello Android! (This was generated dynamically and can add ten and two to make: 15)&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;li&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;ul&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, that's pretty much where I am so far.  I can build an app with static views, and I can confirm that the java that gets generated for my dynamic views seems ok (but won't display on the emulator, despite the apparent lack of exceptions).  Maybe the force_encoding bit is the problem (that'll be my next avenue to explore).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-7539490786591108134?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=0zDJp_03DEM:iOpBUqsURtM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=0zDJp_03DEM:iOpBUqsURtM:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=0zDJp_03DEM:iOpBUqsURtM:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/0zDJp_03DEM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/7539490786591108134/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/08/ruby-on-android-part-2.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/7539490786591108134?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/7539490786591108134?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/0zDJp_03DEM/ruby-on-android-part-2.html" title="Ruby on Android -- Part 2" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/08/ruby-on-android-part-2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcAQn44cCp7ImA9WxNTFEo.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-3889851826816538865</id><published>2009-07-21T00:45:00.005-05:00</published><updated>2009-08-16T22:00:43.038-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-16T22:00:43.038-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile_ruby" /><title>Ruby on Android -- Part I</title><content type="html">Of course, now that I have a &lt;a href="http://forthright.plainlystated.com/2009/07/google-phone.html"&gt;new G1&lt;/a&gt;, I want to start writing apps for it.  Android apps are written in Java, but not having touched that since college, I started looking at ways to get ruby onto it instead.  There was plenty of chatter about the possibility of running jruby on the device, but there are also frameworks that claim to allow you to write apps in ruby and push them to a variety of mobile platforms (android, iPhone, etc).  I'll be hearing a talk about &lt;span&gt;&lt;a href="http://www.appcelerator.com/"&gt;Appcelerator Titanium&lt;/a&gt; at Ruby Hoedown in August, but I haven't gotten into their closed beta, so I'll have to wait to try that out.  The other (similar) solution I came across was &lt;a href="http://rhomobile.com/"&gt;Rhodes&lt;/a&gt;, which is available now (so that's what I'll start with).&lt;br /&gt;&lt;br /&gt;For Android, Rhodes compiles your ruby project to an APK (Android package), which you can push to the Android emulator to test (and eventually to the marketplace).  So, before I get to Rhodes, the first step is to set up a local Android development environment.  I can skip a lot of the stuff Google suggests, since I won't actually be doing java work -- for this first step, all I want is to be able to take an APK and get it running in a local Android emulator.  It took me a while to get this figured out, so hopefully my notes will be helpful to others.&lt;br /&gt;&lt;br /&gt;The first step is to &lt;a href="http://developer.android.com/sdk/1.5_r3/index.html"&gt;download&lt;/a&gt; the Android SDK from Google.  The &lt;a href="http://developer.android.com/sdk/1.5_r3/installing.html"&gt;installation instructions&lt;/a&gt; include a lot of good stuff, but it most of it isn't needed for what I plan on doing.  I already had Java 6 (RE) installed, which seems to work ok.  Since I'm on linux, I followed the linux directions (all the way at the bottom), but the general directions for any OS amount to:&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;Make sure you have Java 1.5 or 1.6 installed&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Install (apt-get) ia32-libs if you're on a 64-bit processor (linux only)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Set up your PATH to include the android tools. (Mac/linux: in your home dir's .bash_profile, add &lt;span style="font-family:monospace;"&gt;"&lt;/span&gt;&lt;code&gt;export PATH=${PATH}:&lt;em&gt;&lt;your_sdk_dir&gt;&lt;/your_sdk_dir&gt;&lt;/em&gt;/tools"&lt;/code&gt;; Windows: right-click on My Computer, and select Properties.  Under the Advanced tab, hit the Environment Variables button, and in the   dialog that comes up, double-click on Path (under System Variables). Add the full path to the    &lt;code&gt;tools/&lt;/code&gt; directory to the path.) &lt;/li&gt;&lt;/ol&gt;You can ignore all the stuff about Eclipse.&lt;br /&gt;&lt;br /&gt;Once you have all that done, you should be able to type '&lt;code&gt;android&lt;/code&gt;' and see some help text (you may need to '&lt;code&gt;source ~/.bash_profile&lt;/code&gt;', or just open a new terminal to reread your profile and get your new PATH).&lt;br /&gt;&lt;br /&gt;The first step is to create a new virtual device.  There are currently three versions of the Android software in the SDK: Version 1.1 (the original), Version 1.5 (the current), and Version 1.5 + Google API.  You can see your available targets using:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ android list targets&lt;br /&gt;Available Android targets:&lt;br /&gt;id: 1&lt;br /&gt;     Name: Android 1.1&lt;br /&gt;     Type: Platform&lt;br /&gt;     API level: 2&lt;br /&gt;     Skins: HVGA (default), QVGA-P, HVGA-P, HVGA-L, QVGA-L&lt;br /&gt;id: 2&lt;br /&gt;     Name: Android 1.5&lt;br /&gt;     Type: Platform&lt;br /&gt;     API level: 3&lt;br /&gt;     Skins: HVGA (default), QVGA-P, HVGA-P, HVGA-L, QVGA-L&lt;br /&gt;id: 3&lt;br /&gt;     Name: Google APIs&lt;br /&gt;     Type: Add-On&lt;br /&gt;     Vendor: Google Inc.&lt;br /&gt;     Description: Android + Google APIs&lt;br /&gt;     Based on Android 1.5 (API level 3)&lt;br /&gt;     Libraries:&lt;br /&gt;      * com.google.android.maps (maps.jar)&lt;br /&gt;          API for Google Maps&lt;br /&gt;     Skins: QVGA-P, HVGA-L, HVGA (default), QVGA-L, HVGA-P&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can find the details about various options when creating an Android Virtual Device (AVD) &lt;a href="http://developer.android.com/guide/developing/tools/avd.html"&gt;here&lt;/a&gt;, but the following is good enough to get you started:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ android create avd -n first_avd15 -t 2&lt;br /&gt;Android 1.5 is a basic Android platform.&lt;br /&gt;Do you wish to create a custom hardware profile [no]&lt;br /&gt;Created AVD 'first_avd15' based on Android 1.5&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To start up your virtual device:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ emulator @first_avd15&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;(I get an error here about audio input missing, but that may be because I don't have a mic on this computer.)&lt;br /&gt;&lt;br /&gt;Now you should see a red generic Android device, with just the word "ANDROID" in the middle.  On my system it takes a while, but eventually you see the "Press menu to unlock" screen, and then you can get to the home screen, where you can do normal Androidy things.    To finish the test, grab a simple Android program in APK form (I used &lt;a href="http://www.androidfreeware.org/download/constitution-1.0.0"&gt;this simple app&lt;/a&gt;).  Download it, and run:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ adb -e install Constitution_1.0.0.apk (or whichever APK you got)&lt;br /&gt;738 KB/s (534155 bytes in 0.706s)&lt;br /&gt;    pkg: /data/local/tmp/Constitution_1.0.0.apk&lt;br /&gt;Success&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;On your emulator, go back to the home screen, and you'll now the the app in the lower tray, with everything else, and it should run without incident.&lt;br /&gt;&lt;br /&gt;If you have any problems duplicating this process, feel free to ping me (comment on this thread).  I worked this out over two nights, and had many false starts, so I could have forgotten to put something that I did to get past a problem.&lt;br /&gt;&lt;br /&gt;My next step will be try and write a simple ruby app and get it to an APK, so I can put it on my emulator.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://techspeak.plainlystated.com/2009/08/ruby-on-android-part-2.html"&gt;Part 2&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-3889851826816538865?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Epn4DVWTWsY:bKXVrslRyNI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Epn4DVWTWsY:bKXVrslRyNI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=Epn4DVWTWsY:bKXVrslRyNI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/Epn4DVWTWsY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/3889851826816538865/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/07/ruby-on-android.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/3889851826816538865?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/3889851826816538865?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/Epn4DVWTWsY/ruby-on-android.html" title="Ruby on Android -- Part I" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/07/ruby-on-android.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIMQ3g-fSp7ImA9WxJRGUs.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-1842747691897300122</id><published>2009-05-21T23:17:00.002-05:00</published><updated>2009-05-21T23:46:22.655-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-21T23:46:22.655-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vim" /><title>Vim Statusline</title><content type="html">To start off my reinvigorated vim education, I looked into why I get a helpful info bar when I have :split windows, but not when I am looking at a single file.  The bar is called the statusline (:help status-line), and you can change the visibility option with&lt;br /&gt;&lt;pre name="code" class="bash:nogutter"&gt;set laststatus=&lt;#&gt;&lt;/pre&gt;It defaults (on my system) to 1, meaning that it only shows for split windows.  To make it always show, set it to 2.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The helpdoc informs us that you can set the content of the statusline with:&lt;br /&gt;&lt;pre name="code" class="bash:nogutter"&gt;set statusline=[some string]&lt;br /&gt;&lt;/pre&gt;[some string] is a printf-style string, with a host of items it can display (:help statusline).  I liked the default (with the rails.vim addition of rails filetype information), but I wanted to also see the buffer number, because I've been playing around with buffer management. Here's what I ended up with, in my .vimrc:&lt;br /&gt;&lt;pre name="code" class="bash:nogutter"&gt;set statusline=&lt;br /&gt;set statusline+=%&lt;\                       " cut at start&lt;br /&gt;set statusline+=%2*[%n%H%M%R%W]%*\        " buffer number, and flags&lt;br /&gt;set statusline+=%-40f\                    " relative path&lt;br /&gt;set statusline+=%=                        " seperate between right- and left-aligned&lt;br /&gt;set statusline+=%1*%y%*%*\                " file type&lt;br /&gt;set statusline+=%10((%l/%L)%)\            " line and column&lt;br /&gt;set statusline+=%P                        " percentage of file&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which gives a statusline like:&lt;br /&gt;&lt;pre name="code" class="bash:nogutter"&gt;[10] app/models/user.rb          [ruby][Rails-model-arb]    (1/276) Top&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/3652396591108344112-1842747691897300122?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=wE7CMkRCC8c:ft6_CW06Zu8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=wE7CMkRCC8c:ft6_CW06Zu8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=wE7CMkRCC8c:ft6_CW06Zu8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/wE7CMkRCC8c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/1842747691897300122/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/05/vim-statusline.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/1842747691897300122?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/1842747691897300122?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/wE7CMkRCC8c/vim-statusline.html" title="Vim Statusline" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/05/vim-statusline.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYBRXk9eCp7ImA9WxJRGUs.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-4457030162080591948</id><published>2009-05-21T22:58:00.005-05:00</published><updated>2009-05-21T23:22:34.760-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-21T23:22:34.760-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vim" /><title>Vim</title><content type="html">I use vim daily for my routine development work, and I get along fine with it.  When I first got into it, I scrambled up the steep learning curve until I got to a plateau where I could be productive, and haven't given it much thought since then.  I can do all the basic stuff (and a few cool tricks), but other than that my editor is pretty low on the list of things I want to devote thought to.&lt;br /&gt;&lt;br /&gt;My position changed, however, when a &lt;a href="http://blog.oneeyedgringo.com/"&gt;coworker&lt;/a&gt; recently decided to jump on the vim bandwagon.  His daily excitement over some newly discovered command or plugin was just what I needed to reignite my interest, and I've started to climb the slopes again.&lt;br /&gt;&lt;br /&gt;I'll share what I discover here. Most of it will probably fall in what I'd consider the intermediate level, but undoubtedly there will be some more basic stuff that I'd never come across (or taken the time to delve into). Part of my problem is that when I was originally learning vim I didn't rely on the help system (which is extensive), but instead played around with things until I was comfortable with them -- so I'll be focusing on :help a lot more this time around, to fill in the gaps. Hopefully my progress will be of some help to other vimers that have been skating by for too long.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-4457030162080591948?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Y6iQMbN4gMQ:-YYAwVTNVPg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Y6iQMbN4gMQ:-YYAwVTNVPg:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=Y6iQMbN4gMQ:-YYAwVTNVPg:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/Y6iQMbN4gMQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/4457030162080591948/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/05/vim.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4457030162080591948?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/4457030162080591948?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/Y6iQMbN4gMQ/vim.html" title="Vim" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/05/vim.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IBQ38_eyp7ImA9WxJREUo.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-1448787099872557976</id><published>2009-05-12T19:12:00.003-05:00</published><updated>2009-05-12T19:45:52.143-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-12T19:45:52.143-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="pitfalls" /><title>Firebug's Console Pitfall</title><content type="html">Beware -- if you leave a reference to the 'console' object in your javascript and deploy it out, your site will not behave!&lt;br /&gt;&lt;br /&gt;I absentmindedly deployed code with a 'console.debug()' in the javascript, and a quick test showed the site to be functioning.  When I tried again in the morning (from my work computer), a dropdown was unpopulated.  I enabled firebug for the site to check things out, but when the page reloaded things were fixed.&lt;br /&gt;&lt;br /&gt;Whenever it was that I learned about the console object, I just took it for granted, and didn't bother to look up anything about it.  So, not only did I not realize that it's provided by firebug (and only available when console is enabled for the site), but I also have been missing out on a variety of other cool methods off of console, such as dir(), trace(), and profile(): &lt;a href="http://getfirebug.com/console.html"&gt;API&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-1448787099872557976?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Az7JmL2NUCY:G6Ncm8Pby8s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=Az7JmL2NUCY:G6Ncm8Pby8s:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=Az7JmL2NUCY:G6Ncm8Pby8s:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/Az7JmL2NUCY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/1448787099872557976/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/05/firebugs-console-pitfall.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/1448787099872557976?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/1448787099872557976?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/Az7JmL2NUCY/firebugs-console-pitfall.html" title="Firebug's Console Pitfall" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/05/firebugs-console-pitfall.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08FRHs9fCp7ImA9WxVUFkw.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-5323533162967478880</id><published>2009-03-21T01:29:00.006-05:00</published><updated>2009-03-21T02:16:55.564-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-21T02:16:55.564-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="caching" /><category scheme="http://www.blogger.com/atom/ns#" term="pitfalls" /><title>Rails Association Caching Pitfalls</title><content type="html">This week at work I was disappointed to find that calling #new on an association collection doesn't add the new instance to the cached collection:&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;&gt;&gt; patrick = Poster.first&lt;br /&gt;=&gt; #&amp;lt;Poster id: 1, name: "Patrick S.", created_at: "2009-03-21 03:55:17", updated_at: "2009-03-21 03:55:17"&gt;&lt;br /&gt;&gt;&gt; patrick.posts.size&lt;br /&gt;=&gt; 0&lt;br /&gt;&lt;br /&gt;&gt;&gt; new_post = patrick.posts.new(:title =&gt; "Another post")&lt;br /&gt;=&gt; #&amp;lt;Post id: nil, title: "Another post", text: nil, poster_id: 1, created_at: nil, updated_at: nil&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts.size&lt;br /&gt;=&gt; 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If I like the post and decide to save it to the database, my cached posts still doesn't get updated:&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;&gt;&gt; new_post.save&lt;br /&gt;=&gt; true&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts.size&lt;br /&gt;=&gt; 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In order to get the collection up-to-date I have to know that this is a trouble spot, and call #reload on the association:&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;&gt;&gt; patrick.posts.reload; patrick.posts.size&lt;br /&gt;=&gt; 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If, instead, I try to push that new instance onto the collection explicitly, it gets saved automatically, which doesn't seem very intuitive (I *much* prefer to have to explicitly save changes to the database):&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;&gt;&gt; patrick.posts &amp;lt;&amp;lt; Post.new(:title =&gt; "pushing onto collection")&lt;br /&gt;Post Create (0.8ms)   INSERT INTO "posts" ("created_at", "title", "poster_id", "updated_at", "text") VALUES('2009-03-21 06:14:03', 'pushing onto collection', 1, '2009-03-21 06:14:03', NULL)&lt;br /&gt;=&gt; [#&amp;lt;Post id: 12, title: "pushing onto collection", text: nil, poster_id: 1, created_at: "2009-03-21 06:14:03", updated_at: "2009-03-21 06:14:03"&gt;]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The right way to do this seems to be the undocumented #build, which does exactly what I was wanting in the first place (create an unsaved instance and append it to the collection):&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;&gt;&gt; patrick.posts.size&lt;br /&gt;=&gt; 0&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts.build(:title =&gt; 'Built')&lt;br /&gt;=&gt; #&amp;lt;Post id: nil, title: "Built", text: nil, poster_id: 1, created_at: nil, updated_at: nil&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts.size&lt;br /&gt;=&gt; 1&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts&lt;br /&gt;=&gt; [#&amp;lt;Post id: nil, title: "Built", text: nil, poster_id: 1, created_at: nil, updated_at: nil&gt;]&lt;br /&gt;&gt;&gt; patrick.posts[0].new_record?&lt;br /&gt;=&gt; true&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(Unfortunately, there seems to be a related problem with the association's #delete/#destroy)&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;&gt;&gt; patrick.posts.size&lt;br /&gt;=&gt; 2&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts.last&lt;br /&gt;=&gt; #&amp;lt;Post id: 13, title: "Another", text: nil, poster_id: 1, created_at: "2009-03-21 06:19:55", updated_at: "2009-03-21 06:19:55"&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts.last.destroy&lt;br /&gt;=&gt; #&amp;lt;Post id: 13, title: "Another", text: nil, poster_id: 1, created_at: "2009-03-21 06:19:55", updated_at: "2009-03-21 06:19:55"&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; patrick.posts.size&lt;br /&gt;=&gt; 2&lt;br /&gt;&gt;&gt; patrick.posts.reload; patrick.posts.size&lt;br /&gt;=&gt; 1&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/3652396591108344112-5323533162967478880?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=vsIRdD_VScE:4DjBfdjI0m8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=vsIRdD_VScE:4DjBfdjI0m8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=vsIRdD_VScE:4DjBfdjI0m8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/vsIRdD_VScE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/5323533162967478880/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/03/rails-association-caching-pitfalls.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/5323533162967478880?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/5323533162967478880?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/vsIRdD_VScE/rails-association-caching-pitfalls.html" title="Rails Association Caching Pitfalls" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/03/rails-association-caching-pitfalls.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYDRXk-fyp7ImA9WxVUEUQ.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-8150535211113047284</id><published>2009-03-16T01:44:00.011-05:00</published><updated>2009-03-16T02:56:14.757-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-16T02:56:14.757-05:00</app:edited><title>Watching Your Logs From The Console</title><content type="html">I've often wished there was a way to see the rails logs right inside the console window, instead of having to switch back and forth betweeh console and a "tail -f" process.  It wasn't hard to find an answer -- Jamis Buck &lt;a href="http://weblog.jamisbuck.org/2007/1/8/watching-activerecord-do-it-s-thing"&gt;blogged about it&lt;/a&gt; back in 2007 -- but it didn't quite do all I was hoping for, so I ended up going a different route, which I think gives a more complete solution.&lt;br /&gt;&lt;br /&gt;The solution that I saw on Jamis' blog was to replace wholesale the rails logger:&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;ActiveRecord::Base.logger = Logger.new(STDOUT)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problems with this are:&lt;br /&gt;1) It must be done before any AR::Base logging is done, and&lt;br /&gt;2) It cannot be undone.&lt;br /&gt;(Both due to the logger object being cached)&lt;br /&gt;&lt;br /&gt;For my needs, I'm interested in the logs for a particular method call, but I don't really want to see all the logs, all the time.  So, I wrote the code that follows (at the end of this post), and put it in my .irbrc file.  It gets around the cached logger object by altering the logger, rather than trying to replace it.  This allows me to turn it on or off mid-session.  For example (from a &lt;a href="http://mindyourweight.net/"&gt;personal side project&lt;/a&gt;):&lt;br /&gt;&lt;pre name="code" class="bash:nogutter"&gt;&lt;br /&gt;&gt;&gt; wr = WeightRecord.first&lt;br /&gt;=&gt; #&amp;lt;WeightRecord id: 1, date: "2007-10-28", weight: 177.0, ... &gt;&lt;br /&gt;...  # More commands, which I don't care to see the logs from ...&lt;br /&gt;&gt;&gt; wr.weight = 176&lt;br /&gt;=&gt; 176&lt;br /&gt;&lt;br /&gt;&gt;&gt; show_log&lt;br /&gt;=&gt; nil&lt;br /&gt;&gt;&gt; wr.save&lt;br /&gt;SQL (0.000154)   BEGIN&lt;br /&gt;SQL (0.069810)   SELECT `date` FROM `weight_records` WHERE (`weight_records`.date = '2007-10-28' AND `weight_records`.user_id = 1 AND `weight_records`.id &lt;&gt; 1)&lt;br /&gt;WeightRecord Update (0.000688)   UPDATE `weight_records` SET `updated_at` = '2009-03-16 01:04:08', `weight` = 176.0 WHERE `id` = 1&lt;br /&gt;SQL (0.004874)   COMMIT&lt;br /&gt;=&gt; true&lt;br /&gt;&lt;br /&gt;&gt;&gt; hide_log&lt;br /&gt;=&gt; nil&lt;br /&gt;...  # More stuff I don't need to see the logs from...&lt;br /&gt;&lt;/weightrecord&gt;&lt;/pre&gt;&lt;br /&gt;(The "SELECT `date`" bit in the logs is because my model has: "validates_uniqueness_of :date, :scope =&gt; :user_id")&lt;br /&gt;&lt;br /&gt;The code:&lt;br /&gt;&lt;pre name="code" class="ruby:nogutter"&gt;&lt;br /&gt;def show_log&lt;br /&gt;  unless @log_buffer_size&lt;br /&gt;    @log_file = Rails.logger.instance_variable_get("@log")&lt;br /&gt;    @log_level = Rails.logger.level&lt;br /&gt;    @log_buffer_size = Rails.logger.auto_flushing&lt;br /&gt;  end&lt;br /&gt;  Rails.logger.flush&lt;br /&gt;  Rails.logger.instance_variable_set("@log", STDOUT)&lt;br /&gt;  Rails.logger.level = Logger::DEBUG&lt;br /&gt;  Rails.logger.auto_flushing = 1&lt;br /&gt;  nil&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def hide_log&lt;br /&gt;  if @log_buffer_size&lt;br /&gt;    Rails.logger.instance_variable_set("@log", @log_file)&lt;br /&gt;    Rails.logger.level = @log_level&lt;br /&gt;    Rails.logger.auto_flushing = @log_buffer_size&lt;br /&gt;  end&lt;br /&gt;  nil&lt;br /&gt;end&lt;br /&gt;&lt;/weightrecord&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-8150535211113047284?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=t4baonS3o7M:J84o6jmUDfQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=t4baonS3o7M:J84o6jmUDfQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=t4baonS3o7M:J84o6jmUDfQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/t4baonS3o7M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/8150535211113047284/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/03/watching-your-logs-from-console.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/8150535211113047284?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/8150535211113047284?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/t4baonS3o7M/watching-your-logs-from-console.html" title="Watching Your Logs From The Console" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/03/watching-your-logs-from-console.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUDRXo8fCp7ImA9WxVUFk8.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-2692000772047923853</id><published>2009-03-04T02:23:00.001-06:00</published><updated>2009-03-21T02:24:34.474-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-21T02:24:34.474-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="misc." /><title>When Your Data Leaves Home Without You</title><content type="html">Those that know me best know that I much prefer to keep my data on my own servers, as opposed to using services such as PicasaWeb, Blogspot, and github.  Something about giving up possession of my original content doesn't sit quite right with me -- maybe it's my own experience with the "possession is nine-tenths of the law" adage, or maybe I'm just wary of free services.  There's also the problem of building up a brand that is on someone else's domain -- whatever popularity my content gets should be associated with my domain, not the provider's.  Whatever the reason, I am generally willing to put up with poorer performance (etc.) in order to host my services myself.&lt;br /&gt;&lt;br /&gt;For my two new blogs I started out looking for a rails plugin, to add into plainlystated.com.  I didn't find anything that looked mature, and I didn't feel like coding it myself (since these things always end up taking a lot longer than they initially seem when you add in captchas, admin features, layouts, etc).  I got the latest version of Typo, but it was running at almost 60 megs of RAM, which is a lot for my little VPS.  Plus, "satellite blogs" (two separate blogs running on one Typo) aren't even supported "yet", so it was gonna be a matter of hacking Typo (maybe with a third-party plugin), or running two instances, and both options seemed like a waste of semi-precious resources.&lt;br /&gt;&lt;br /&gt;So, as you can see, I broke down and went with a free hosted solution.  I looked briefly at wordpress, blogspot, and livejournal, but they all seem "good enough" so I went with ole' reliable: Google.&lt;br /&gt;&lt;br /&gt;In this case, there seem to be some substantial benefits to going with Blogspot:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I don't use my own resources,&lt;/li&gt;&lt;li&gt;I don't have to worry about security, system maintenance, etc.,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I get automatic security updates and feature upgrades,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I get plenty of free templates,&lt;/li&gt;&lt;li&gt;It "just works".&lt;/li&gt;&lt;/ul&gt;Blogspot also provides the option to host the blog from a subdomain of your own (which is how I have techspeak.plainlystated.com instead of techspeak.blogspot.com), which is pretty cool, and mitigates my concerns about building up my own brand.&lt;br /&gt;&lt;br /&gt;Hopefully this decision will end up making me more comfortable with taking advantage of all the great free providers out there (maybe I'll be linking to a PicasaWeb album before long).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-2692000772047923853?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=rGtsNbV_DeI:BP_RJletdt0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=rGtsNbV_DeI:BP_RJletdt0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=rGtsNbV_DeI:BP_RJletdt0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/rGtsNbV_DeI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/2692000772047923853/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/03/when-your-data-leaves-home-without-you.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/2692000772047923853?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/2692000772047923853?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/rGtsNbV_DeI/when-your-data-leaves-home-without-you.html" title="When Your Data Leaves Home Without You" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/03/when-your-data-leaves-home-without-you.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUDRXo8fCp7ImA9WxVUFk8.&quot;"><id>tag:blogger.com,1999:blog-3652396591108344112.post-7795680797820318325</id><published>2009-03-03T02:14:00.000-06:00</published><updated>2009-03-21T02:24:34.474-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-21T02:24:34.474-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="misc." /><title>New Blog</title><content type="html">Just a quick post to introduce my new blog...  This, along with my other new blog &lt;a href="http://forthright.plainlystated.com"&gt;forthright.plainlystated.com&lt;/a&gt; (non-technical) are meant to be my new home in the ether.&lt;br /&gt;&lt;br /&gt;This blog (techspeak.plainlystated.com) will generally be about my adventures in Ruby on Rails, as I continue growing my expertise in the field.  (I have been working professionally with Rails for about 2 years, including the past 1.5 years at Medical Decision Logic working on medical research management software.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3652396591108344112-7795680797820318325?l=techspeak.plainlystated.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=hWVi99Bx4oU:PyTax00tdx4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/plainlystated/xtwL?a=hWVi99Bx4oU:PyTax00tdx4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/plainlystated/xtwL?i=hWVi99Bx4oU:PyTax00tdx4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/plainlystated/xtwL/~4/hWVi99Bx4oU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://techspeak.plainlystated.com/feeds/7795680797820318325/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techspeak.plainlystated.com/2009/03/new-blog.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/7795680797820318325?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3652396591108344112/posts/default/7795680797820318325?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/plainlystated/xtwL/~3/hWVi99Bx4oU/new-blog.html" title="New Blog" /><author><name>Patrick Schless</name><uri>http://www.blogger.com/profile/04639385933761913460</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09990990906624654531" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://techspeak.plainlystated.com/2009/03/new-blog.html</feedburner:origLink></entry></feed>
