<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cosine Jeremiah and his Musings &#187; Ruby</title>
	<atom:link href="http://cosine.org/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://cosine.org</link>
	<description>Life and Ruby and Security</description>
	<lastBuildDate>Sat, 10 Apr 2010 08:48:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>Rails, Django, and Just-Barely-Enough CSRF Protection</title>
		<link>http://cosine.org/2010/04/10/rails-django-just-barely-enough-csrf-protection/</link>
		<comments>http://cosine.org/2010/04/10/rails-django-just-barely-enough-csrf-protection/#comments</comments>
		<pubDate>Sat, 10 Apr 2010 08:48:46 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://cosine.org/?p=89</guid>
		<description><![CDATA[This week I found what I thought was a bug in Rails 2.3: it does not check the anti-CSRF authenticity token for AJAX requests. Due to years of experience with Rails I knew that this was not the previous behavior I have come to expect, so I dug around and learned that this behavior was [...]]]></description>
			<content:encoded><![CDATA[<p>This week I found what I thought was a bug in Rails 2.3: it does not check the anti-CSRF authenticity token for AJAX requests.  Due to years of experience with Rails I knew that this was not the previous behavior I have come to expect, so I dug around and learned that this behavior was intentionally changed some months back.  Due to same-origin policy for XMLHttpRequests, the existence of the X-Requested-With header is considered sufficient validation of the request.  Some details of the commit and comments on it can be found following <a href="http://github.com/rails/rails/commit/523f3ba8daf4968267eb4597bc88359a6337cf90#comments">this Github link</a>.  Much thanks to my friend Cory Scott of <a href="http://www.matasano.com/">Matasano</a> for bringing this to my attention.</p>
<p>Okay, fine&mdash;sort of.  I have a beef with this.</p>
<p>Good security practice is about implementing layers of security, and this flies in the face of that.  If certain other vulnerabilities are present, the most obvious one being HTTP response splitting, then CSRF is once again possible.  Any vulnerability that could allow custom headers to be inserted in a CSRF request now makes them possible because the authenticity token is bypassed by a custom header.</p>
<p>In my opinion, if a site has data worth protecting with an anti-CSRF authenticity token, there&#8217;s no reason not to use it for all requests that can alter that data.  Doing the bare minimum is what I call <em>Just-Barely-Enough Security</em>.</p>
<p>Note that Rails 3.0 handles CSRF protection differently (within Rack), and I have not examined it; the above comments apply only to Rails 2.x.</p>
<p>So it turns out that Rails is not the only web framework out there where the CSRF protection was in the just-barely-enough category.  I have also been working on a Django 1.1 project recently, and in doing so I have found another category of just-barely-enough security (fixed in Django 1.2).  Django 1.1 generates the authenticity token in a somewhat weak manner, but it is not weak enough that it is exploitable by itself.  The weakness is that the authenticity token is the MD5 hash of a site-wide secret concatenated by the session ID (in contrast, Rails 2.3 and Django 1.2 generate a completely random token for each session).  Because of how MD5 hashes are computed, an attacker could potentially learn the state of the MD5 computation up to the point of hashing the site-wide secret and himself compute any authenticity token given a session ID without further consulting the Django server.  However, this is not an issue by default because Django&#8217;s session fixation protection prevents it from responding with session IDs that it did not generate, so the attacker cannot build up the necessary information to perform the attack.  But if something were to be configured wrong on the Django server and a session fixation attack were to be possible, then the attacker would have more avenues for exploitation than just using session fixation on the victim directly.</p>
<p>Even worse would be a situation where the session fixation issue was found and repaired, but not before an attacker gleaned the necessary information to generate authenticity tokens for the site.  The site administrator would think he closed the security hole, but his site may still be exploitable based on previously leaked information.  That would be rather unfortunate.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2010/04/10/rails-django-just-barely-enough-csrf-protection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Thoughts on Pair Programming</title>
		<link>http://cosine.org/2010/03/10/thoughts-pair-programming/</link>
		<comments>http://cosine.org/2010/03/10/thoughts-pair-programming/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 05:28:36 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://cosine.org/?p=85</guid>
		<description><![CDATA[I have recently been exposed to the first pair programming in my career, and I want to quickly share some thoughts on it. Honestly, at first I found it a little frustrating. There I was spending half my time watching someone else implement some stuff, and my brain simultaneously stuck elsewhere solving world hunger while [...]]]></description>
			<content:encoded><![CDATA[<p>I have recently been exposed to the first pair programming in my career, and I want to quickly share some thoughts on it.</p>
<p>Honestly, at first I found it a little frustrating.  There I was spending half my time watching someone else implement some stuff, and my brain simultaneously stuck elsewhere solving world hunger while trying to be &#8220;helpful&#8221; to that other guy with me.  It took a few weeks before the benefits really started dawning on me and also to appreciate the contribution I make when not the guy with the keyboard.  I think many people have recounted much of what is great about pair programming, but the one that I have not heard that really makes me giddy is that <em>your partner prevents you from being lazy</em>.</p>
<p>In particular, I do not mean that your partner prevents you from using things like email as a distraction from getting stuff done (another benefit that others have recounted).  Instead I mean that when you are racing to complete a programming task and you encounter a decision to: (1) hack it and jam something in place quickly, or (2) Doing It Right but burn up extra time doing so.  Without a partner you typically choose #1 while lamenting that you did not choose #2.  You add to your technical debt and bad karma and you are ridden with guilt; it is a double whammy!</p>
<p>With a partner, what happens instead is that you suggest #1 to your partner, but regardless of whether your partner can discern whether #1 is Doing It Right he can see your hesitation and draws your thoughts out of you about #2.  Before you know it, he is excited to see you through to Doing It Right!  Your heart leaps in joy and later, when you go home for the day, you smile just a little more when your sweetheart asks, &#8220;how was work today, honey?&#8221; <img src='http://cosine.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2010/03/10/thoughts-pair-programming/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mephisto</title>
		<link>http://cosine.org/2008/08/23/mephisto/</link>
		<comments>http://cosine.org/2008/08/23/mephisto/#comments</comments>
		<pubDate>Sat, 23 Aug 2008 08:18:03 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/?p=50</guid>
		<description><![CDATA[I have spent a lot of hours in the past week working with Mephisto. Mephisto is a blogging platform with aims of eventually being a full-fledged CMS. Overall I like it, but I am uncertain if it is a platform I ought to continue working with at this point. Here are the highlights of the [...]]]></description>
			<content:encoded><![CDATA[<p>I have spent a lot of hours in the past week working with <a href="http://www.mephistoblog.com/">Mephisto</a>.  Mephisto is a blogging platform with aims of eventually being a full-fledged CMS.  Overall I like it, but I am uncertain if it is a platform I ought to continue working with at this point.</p>
<p>Here are the highlights of the pros:</p>
<ul>
<li>It is written in <a href="http://www.rubyonrails.org/">Rails</a>, which is a platform I know well and therefore can extend rather easily.</li>
<li>The site can be split into multiple sections, each of which can be its own blog and have its own RSS feed, or which can be a single page.</li>
<li>Themes!  Mephisto can be themed, and it is easy to write new ones using one or more of several template languages.</li>
<li>It allows multiple layouts to allow for different looks for each section of the site.</li>
<li>Articles can be formatted in with Textile, Markdown, or just plain HTML.  I was able to integrate TinyMCE without much trouble as well.</li>
</ul>
<p>But there are also the cons:</p>
<ul>
<li>The current version is 0.8.  That is not quite 1.0, and I wager that the reason it is not at 1.0 is related to the various little bugs that I have found.</li>
<li>Sometimes Mephisto will select the wrong layout for a page and it is difficult to figure out why.  Fortunately, these situations are limited to &#8220;Preview this Post&#8221; and the &#8220;permanent links&#8221; to articles that represent pages that normally do not get linked to.</li>
<li>Mephisto has plugins and themes, but it is difficult to find useful plugins and more than a small number of publicly available themes.</li>
</ul>
<p><!-- adman --></p>
<p>I think Mephisto is a better platform than <a href="http://www.radiantcms.org/">Radiant</a> at this point, and in my opinion it gives Rails a reasonably usable blogging platform.  Before committing more time to it, however, I think I will take a look at the much touted <a href="http://drupal.org/">Drupal</a>.  I have been meaning to take a look at it anyway. <img src='http://cosine.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2008/08/23/mephisto/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Unleash the Arc!</title>
		<link>http://cosine.org/2008/02/06/unleash-arc/</link>
		<comments>http://cosine.org/2008/02/06/unleash-arc/#comments</comments>
		<pubDate>Wed, 06 Feb 2008 07:08:53 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[arc]]></category>
		<category><![CDATA[paul graham]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2008/02/06/unleash-arc/</guid>
		<description><![CDATA[I just found out that Paul Graham has unleashed Arc upon the world after years and years of teasing us. This is exciting, particularly for what will happen to Ruby. All of the nifty features that make Arc awesome will be extracted into a few Ruby gems in the next 2&#8211;4 weeks, and everything that [...]]]></description>
			<content:encoded><![CDATA[<p>I just found out that <a href="http://www.paulgraham.com/">Paul Graham</a> <a href="http://www.paulgraham.com/arc0.html">has unleashed</a> <a href="http://arclanguage.org/">Arc</a> upon the world after <a href="http://www.paulgraham.com/arcll1.html">years</a> and <a href="http://www.paulgraham.com/ilc03.html">years</a> of teasing us.  This is exciting, particularly for what will happen to Ruby.  All of the nifty features that make Arc awesome will be extracted into a few Ruby gems in the next 2&ndash;4 weeks, and everything that Paul put into Arc will be available for Ruby.</p>
<p>But Cosine, you might say, Paul developed Arc so that the <em>language</em> would have nifty breakthrough features unlike any ever seen before to make code more concise!  Without the base language support for these features, Ruby will not beat Arc at its own game!</p>
<p>Well, someone has already <a href="http://arc-challenge.heroku.com/">written a library</a> (it should be reformatted properly into one, anyway) in response to the <a href="http://www.paulgraham.com/arcchallenge.html">Arc Challenge</a> that implements part of the Arc standard library, exposing for Ruby any language features in Arc that Paul was trying to showcase in the Arc Challenge.</p>
<p>Paul, please give us a challenge that shows a fundamental language design difference rather than displaying a gap in the presently available libraries.  I know you are a smart cookie, so you must be hiding something up that sleeve.</p>
<p>Actually, I can think of one advantage Arc has over Ruby.  Arc is Lisp whereas Ruby is not, and following from that Arc has macros while Ruby has ugly workarounds to fake macro writing.  But everyone already knows that.  Hmmm, maybe what we really want to do is have all our Ruby gems and Rails made available for Arc?  Arc on Rails, anyone?  I think that would be pleasant.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2008/02/06/unleash-arc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Looking at Ruby on Rails</title>
		<link>http://cosine.org/2008/02/05/ruby-rails/</link>
		<comments>http://cosine.org/2008/02/05/ruby-rails/#comments</comments>
		<pubDate>Tue, 05 Feb 2008 20:42:20 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2008/02/05/ruby-rails/</guid>
		<description><![CDATA[Are you stuck in a J2EE framework that leaves you feeling like this? &#60;statement&#62;&#60;personal&#62;&#60;timeframe&#62;&#60;someday&#62;&#60;subject&#62;I&#60;/subject&#62;&#60;action how="at"&#62;look&#60;/action&#62;&#60;object&#62;&#60;name&#62;ruby&#60;/name&#62;&#60;modifier type="on"&#62;rails&#60;/modifier&#62;&#60;/object&#62;&#60;/someday&#62;&#60;/timeframe&#62;&#60;/personal&#62;&#60;/statement&#62; Why wait? Get out there and get started with Rails today!]]></description>
			<content:encoded><![CDATA[<p>Are you stuck in a J2EE framework that leaves you feeling like this?</p>
<p><code>&lt;statement&gt;&lt;personal&gt;&lt;timeframe&gt;&lt;someday&gt;&lt;subject&gt;I&lt;/subject&gt;&lt;action how="at"&gt;look&lt;/action&gt;&lt;object&gt;&lt;name&gt;ruby&lt;/name&gt;&lt;modifier type="on"&gt;rails&lt;/modifier&gt;&lt;/object&gt;&lt;/someday&gt;&lt;/timeframe&gt;&lt;/personal&gt;&lt;/statement&gt;</code></p>
<p>Why wait?  Get out there and <a href="http://www.rubyonrails.org/">get started with Rails</a> today! <img src='http://cosine.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2008/02/05/ruby-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>irb: Learning Ruby Quick</title>
		<link>http://cosine.org/2007/10/17/irb-learning-ruby-quick/</link>
		<comments>http://cosine.org/2007/10/17/irb-learning-ruby-quick/#comments</comments>
		<pubDate>Wed, 17 Oct 2007 12:00:44 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/10/17/irb-learning-ruby-quick/</guid>
		<description><![CDATA[In my previous post I introduced the idea of using irb as a desktop calculator. If you are new to Ruby, however, using irb can have the side effect of teaching you Ruby. Everything you type in irb is a Ruby statement. The response you get from irb is the value Ruby returns from the [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous post I introduced the idea of using irb as a desktop calculator.  If you are new to Ruby, however, using irb can have the side effect of teaching you Ruby.  Everything you type in irb is a Ruby statement.  The response you get from irb is the value Ruby returns from the evaluation of the statement you type.  You can use this to try things out in Ruby to see how it behaves.  Here is an example exploring how a Ruby Array handles some given Range objects as arguments to the &#8220;indexing&#8221; method <code>[]</code>:</p>
<pre>
irb(main):001:0&gt; <b>a = [1, 2, 3, 4, 5]</b>
=&gt; [1, 2, 3, 4, 5]
irb(main):002:0&gt; <b>a[1..-1]</b>
=&gt; [2, 3, 4, 5]
irb(main):003:0&gt; <b>a[1..a.size]</b>
=&gt; [2, 3, 4, 5]
irb(main):004:0&gt; <b>a[1..&#46;-1]</b>
=&gt; [2, 3, 4]
</pre>
<p>Now we just saw first hand some of how we manipulate Arrays in Ruby.  But what if we are curious about what else we can do with an Array?  It would be really nice if we could quickly get a list of methods available for my Array.  Oh, but we can!  Every Ruby object has a <code>methods</code> method that returns an Array populated with the names all the messages it responds to.</p>
<pre>
irb(main):005:0&gt; <b>a.methods</b>
=&gt; [&#34;select&#34;, &#34;[]=&#34;, &#34;inspect&#34;, &#34;compact&#34;, &#34;&lt;&lt;&#34;, &#34;&amp;&#34;, &#34;clone&#34;,
&#34;method&#34;, <em>..&#46; (over 100 other methods) ..&#46;</em>, &#34;unshift&#34;,
&#34;sort_by&#34;, &#34;to_yaml_properties&#34;, &#34;fill&#34;, &#34;max&#34;, &#34;is_a?&#34;,
&#34;uniq!&#34;, &#34;[]&#34;]
</pre>
<p>Oh, that is a lot of methods!  My version of Ruby/irb returned 128 methods for the object, and they are hard to read all mixed up like that.  Good thing we can sort them, too:</p>
<pre>
irb(main):006:0&gt; <b>a.methods.sort</b>
=&gt; [&#34;&amp;&#34;, &#34;*&#34;, &#34;+&#34;, &#34;-&#34;, &#34;&lt;&lt;&#34;, &#34;&lt;=&gt;&#34;, &#34;==&#34;, &#34;===&#34;, <em>..&#46; (over 100
other methods) ..&#46;</em>, &#34;uniq&#34;, &#34;uniq!&#34;, &#34;unshift&#34;, &#34;untaint&#34;,
&#34;values_at&#34;, &#34;yaml_initialize&#34;, &#34;zip&#34;, &#34;|&#34;]
</pre>
<p><!-- adman --></p>
<p>By scanning the methods available to an object you can get an idea of what you can do with it before you even look at proper documentation (which you want to have handy, too).  Using the <code>methods</code> method from irb is also a fast way to recall the name of a method if you forget it and your text editor or IDE does not help you figure it out.  I sometimes just try out methods unknown to me just to see what happens, and then I check the documentation shortly thereafter to ensure I understand it.</p>
<p>The most important aspect of irb that enabled me to learn Ruby and keep up with changes in the language was the ability to vet out short bits of code before putting them into a program.  For example, if I need to ensure a complicated regular expression will match what I want it to, I can do the initial testing in irb.  Then those tests done in irb that supply confidence that the regular expression is correct are copied into the unit tests.  Here is a simple example to illustrate the idea:</p>
<pre>
irb(main):007:0&gt; <b>&#39;foo bar baz&#39; =~ /&#92;&lt;bar&#92;&gt;/</b>
=&gt; nil
</pre>
<p>Oops!  I expected an Integer result, which would denote there was a match.  However, I forgot I was working in Ruby instead of an old version of grep, and the notations denoting a word boundary in regular expressions are different between the two.  It is easily fixed:</p>
<pre>
irb(main):008:0&gt; <b>&#39;foo bar baz&#39; =~ /&#92;bbar&#92;b/</b>
=&gt; 4
</pre>
<p>One other trick I employ in irb is to get a list of currently loaded classes, at least as defined at the top level (i.e. a class within a class or module, like <code>Net::HTTP</code>, will not show up, but <code>Net</code> will and then one could drill down from there).  This can be done because every class can be identified by a constant value, and a list of these constants can be obtained from the <code>Object</code> class using the <code>constants</code> class method:</p>
<pre>
irb(main):009:0&gt; <b>Object.constants.sort</b>
=&gt; [&#34;ARGF&#34;, &#34;ARGV&#34;, &#34;ArgumentError&#34;, &#34;Array&#34;, &#34;BasicSocket&#34;,
&#34;Bignum&#34;, &#34;Binding&#34;, &#34;Buffering&#34;, <em>..&#46; (over 100 other entries)
..&#46;</em>, &#34;UNIXserver&#34;, &#34;UNIXsocket&#34;, &#34;URI&#34;, &#34;UnboundMethod&#34;,
&#34;VERSION&#34;, &#34;YAML&#34;, &#34;ZeroDivisionError&#34;, &#34;Zlib&#34;]
</pre>
<p>Not all of the entries returned are classes (e.g. <code>ARGF</code> and <code>ARGV</code>), but it does not hurt to know about the other defined constants, too.</p>
<p>With irb at my disposal learning Ruby was a snap, and it was very fun.  If you have not yet had the pleasure of learning Ruby then perhaps irb can make your journey more fun, too.  Let me know if you try it out!</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/10/17/irb-learning-ruby-quick/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>irb: The New Desktop Calculator</title>
		<link>http://cosine.org/2007/10/11/irb-desktop-calculator/</link>
		<comments>http://cosine.org/2007/10/11/irb-desktop-calculator/#comments</comments>
		<pubDate>Thu, 11 Oct 2007 12:00:17 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/10/11/irb-desktop-calculator/</guid>
		<description><![CDATA[One of the things I love about Ruby is that it comes with irb. It is short for Interactive Ruby, and it is a command line tool to interact with an instance of the Ruby interpreter. To start it up just run irb from the command line (Interactive Ruby is a menu option in the [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things I love about Ruby is that it comes with irb.  It is short for <strong>I</strong>nteractive <strong>R</strong>u<strong>b</strong>y, and it is a command line tool to interact with an instance of the Ruby interpreter.  To start it up just run <code>irb</code> from the command line (Interactive Ruby is a menu option in the most common Windows Ruby package).  One of my most frequent uses of irb is as a calculator:</p>
<pre>
irb(main):001:0&gt; <b>1465 + 1723</b>
=&gt; 3188
</pre>
<p>Simple addition is not too exciting, but that&#8217;s just the beginning.  When Ruby is at your fingertips, the sky is the limit (limited by your imagination, of course).  You can sum up a whole list of numbers quickly:</p>
<pre>
irb(main):002:0&gt; <b>[1, 2, 3, 4, 5, 6].inject(0) { |x, y| x + y }</b>
=&gt; 21
</pre>
<p>Use variables to store values or add to them:</p>
<pre>
irb(main):003:0&gt; <b>a = 515</b>
=&gt; 515
irb(main):004:0&gt; <b>a += 23</b>
=&gt; 538
</pre>
<p>Or perhaps you need a special function to crunch your numbers today?  Just define it, possibly as an instance method for the Array or Integer classes, and then have a blast with it:</p>
<pre>
irb(main):005:0&gt; <b>class Array</b>
irb(main):006:1&gt;   <b>def sum_of_squares</b>
irb(main):007:2&gt;     <b>inject(0) { |s, x| s + x * x }</b>
irb(main):008:2&gt;   <b>end</b>
irb(main):009:1&gt; <b>end</b>
=&gt; nil
irb(main):010:0&gt; <b>[1, 2, 3, 4, 5, 6].sum_of_squares</b>
=&gt; 91
</pre>
<p>Take advantage of some mathematical constants!  They are available, too, using the Ruby constants shown below.</p>
<pre>
irb(main):011:0&gt; <b>Math::PI</b>
=&gt; 3.14159265358979
irb(main):012:0&gt; <b>Math::E</b>
=&gt; 2.71828182845905
</pre>
<p>Finally, there is just one thing to note.  If you are doing division and want a decimal point in your results then you need to make sure you are using at least one floating point precision number in your statement (otherwise the result is an integer dividend):</p>
<pre>
irb(main):013:0&gt; <b>2352.0 / 17</b>
=&gt; 138.352941176471
irb(main):014:0&gt; <b>2352 / 17</b>
=&gt; 138
</pre>
<p><!-- adman --></p>
<p>Using irb as a desktop calculator is really just scratching the surface of what one can do, but I think it is a rather cool application of it.  If you have never used irb, or even Ruby, go ahead and give it a try!  I hope you find it just as useful as I do.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/10/11/irb-desktop-calculator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Moving Up on Mini-Scripting</title>
		<link>http://cosine.org/2007/09/10/miniscripting/</link>
		<comments>http://cosine.org/2007/09/10/miniscripting/#comments</comments>
		<pubDate>Mon, 10 Sep 2007 12:00:37 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/09/10/miniscripting/</guid>
		<description><![CDATA[After my previous post on ad hoc scripting I had an example come up in my own work. I needed to search through some web logs for all hits in August to three servers from a pair of IP addresses. Below is the actual command line script I used, except I changed some identifying information [...]]]></description>
			<content:encoded><![CDATA[<p>After my <a href="http://www.cosine.org/2007/09/05/scripting-command-line/">previous post on ad hoc scripting</a> I had an example come up in my own work.  I needed to search through some web logs for all hits in August to three servers from a pair of IP addresses.  Below is the actual command line script I used, except I changed some identifying information and extended the script from a single line to multiple lines for clarity.  This script reduced the logs to a file that details which web server was it, which IP address the request came from, and the date and time of the request:</p>
<pre>
let D=1; while (( D <= 31 )); do
  DD=$(printf "%02d" $D)
  for M in server-01 server-02 server-03 ; do
    gzip -cd $M/weblog.200708$DD.gz | \\
        perl -anle 'print "'$M' $F[0] $F[3]"
            if $F[0] =~ /^10\.1\.2\.[34]$/'
  done
  let D=D+1
done > ~/log_report
</pre>
<p>There are a few things I want to point out about this mini-script:</p>
<ol>
<li>Iteration is performed on an index value (<code>$D</code>), tested using Kornshell&#8217;s double parentheses syntax, and incremented using a <code>let</code> statement.</li>
<li>It makes use of a Perl one-liner to rearrange the data on each line and only print that data that is relevant to the task at hand.</li>
<li>I send the output of the entire thing to a file by redirecting it after the final &#8220;<code>done</code>&#8221; statement.</li>
</ol>
<p>None of these things is really a big deal to me anymore, but I have noticed many people do not think or know you can do these things.  I think that if you do realize it then you can come up with some more powerful mini-scripts from your command line.</p>
<p>I noted before that I use the <a href="http://zsh.sourceforge.net/">Z shell</a>, a Bourne compatible shell.  While the above mini-script will not work in the Bourne shell itself, it should also work in the Kornshell and the Bourne Again shell, though your mileage may vary.</p>
<p><b>Incrementing an Index</b></p>
<p>The generic script code for iterating over an increasing numeric index is:</p>
<pre>
let I=0; while (( I < 10 )); do
  ... <em>your code here</em> ...
  let I=I+1
done
</pre>
<p>If your shell is a traditional Bourne shell that does not support let-statements and double parentheses notation, then you may do this:</p>
<pre>
I=0; while [ $I -lt 10 ]; do
  ... <em>your code here</em> ...
  I=`echo $I + 1 | bc`
done
</pre>
<p>If you have a small set of numbers to iterate over then it is often still faster to just type them all out in a for-statement, but that stops being true when you have a large set of numbers.</p>
<p><!-- adman --></p>
<p><b>Invoking Perl and/or Ruby</b></p>
<p>This technique should not be alien to someone that writes shell scripts.  Even if you never thought to invoke Perl and/or Ruby in your scripts, you have probably used sed and awk.  In the above example I could have used awk instead of Perl, but Perl seemed like a better choice at the time.  Ruby and Perl have flags that help them be more useful on the command line, and in fact they can both become more powerful replacements for sed and awk.  Some flags are:</p>
<p><code><b>-n</b></code>: I call this the awk-mode flag.  It causes both Ruby and Perl to loop on each line of the input, putting that line of input into <code>$_</code>.</p>
<p><code><b>-p</b></code>: I call this the sed-mode flag.  It causes both Ruby and Perl to loop on each line of input like <code>-n</code>, but also prints the value of <code>$_</code> at the end of the loop (presumibly you have modified it).</p>
<p><code><b>-a</b></code>: This is often used with <code>-n</code>, though it could also be used with <code>-p</code>.  As each line of input is read, it is split and the resulting array stored in @F (Perl) or $F (Ruby).  I used this feature in the above mini-script to limit which fields are output to the report I generated.</p>
<p><code><b>-l</b></code>: This flag causes lines output to be terminated with a newline.  It also causes lines of data input via <code>-n</code> and <code>-p</code> to be auto-chomped.</p>
<p><code><b>-e</b></code>: The most important flag for one-liners!  This causes Perl and Ruby to take their commands from the argument given after <code>-e</code>.  It may be specified multiple times to issue more code from the command line.</p>
<p><code><b>-i</b></code>: If you want to edit a file in-place you can use this flag to tell Perl or Ruby to edit each file of input instead of leaving those files untouched.  You can also opt to provide an extension to be used for a backup of the input.  Note that because of the syntax for the optional extension use, you should check the man page for usage.</p>
<p><b>Redirecting Output</b></p>
<p>You can redirect output from any part of a script.  Most people focus on redirection of individual commands, but that causes one to have to keep appending data to an output file.  One does not need to do that!  Just redirect your output after the &#8220;<code>done</code>&#8221; and you will capture all of the output from all of the commands inside the loop.  Spiffy, eh?</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/09/10/miniscripting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Method Aliasing and Aspect-Oriented Programming</title>
		<link>http://cosine.org/2007/08/30/method-aliasing-aspect-oriented-programming/</link>
		<comments>http://cosine.org/2007/08/30/method-aliasing-aspect-oriented-programming/#comments</comments>
		<pubDate>Thu, 30 Aug 2007 12:00:29 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/08/30/method-aliasing-aspect-oriented-programming/</guid>
		<description><![CDATA[One of the things that I have recently played with in Ruby is a sort of aspect-oriented programming. I say &#8220;sort of&#8221; because Ruby is not really an aspect-oriented language out of the box, but with some inconvenient constructs one can approach problems in this manner, using this mindset. I touched this because I am [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things that I have recently played with in Ruby is a sort of <a href="http://en.wikipedia.org/wiki/Aspect_oriented_programming">aspect-oriented programming</a>.  I say &#8220;sort of&#8221; because Ruby is not really an aspect-oriented language out of the box, but with some inconvenient constructs one can approach problems in this manner, using this mindset.  I touched this because I am writing extensions to another program already written in this style.  I think a lot of Rubyists do this when modularizing their code.  What I saw was that one of the classes I needed to modify was modularized into several components:</p>
<pre>
class Shape
  module CurvySides
    # ... code supporting curvy sides here ...
  end

  module StraightSides
    # ... code supporting straight sides here ...
  end

  include CurvySides, StraightSides
end
</pre>
<p>Actually, each concern was in a separate file:</p>
<pre>
require 'shape/curvy_sides'
require 'shape/straight_sides'

class Shape
  include CurvySides, StraightSides
end
</pre>
<p><span id="more-28"></span><!-- adman --></p>
<p>How is <em>that</em> for separation?  But wait, you say&#8230; what if including each concern requires a change in behavior to the same method?  You cannot just define the whole method in both modules; if you ran one the other would not get to assert its behavior.</p>
<p>The solution lies in Ruby&#8217;s method aliasing mechanism.  Each module defines its own version of the method assuming that there is another, previously defined, version of the method to be called.</p>
<pre>
class Shape
  def side_length
    0
  end

  module CurvySides
    def self.included (base)
      base.send :alias_method, :side_length_without_curvy_sides, :side_length
      base.send :alias_method, :side_length, :side_length_with_curvy_sides
    end

    def side_length_with_curvy_sides
      side_length_without_curvy_sides + (... other computation ...)
    end
  end

  module StraightSides
    def self.included (base)
      base.send :alias_method, :side_length_without_straight_sides, :side_length
      base.send :alias_method, :side_length, :side_length_with_straight_sides
    end

    def side_length_with_straight_sides
      side_length_without_straight_sides + (... other computation ...)
    end
  end

  include CurvySides, StraightSides
end
</pre>
<p>So it is not the prettiest code, but it effects the separation of programming concerns a la aspect-oriented programming.  For version one of anything I write I will not be using this much, but I think that before someone publishes their work they should consider modularizing it in this way.  In fact, this architecture has been a great help to me as I extend the functionality of the class myself.  I am simply writing my modifications as modules that are included into the class just like its base functionality.  Sometimes they augment existing methods, and I have to make the calls to #alias_method for the class, and sometimes I do not.  In any case, it is fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/08/30/method-aliasing-aspect-oriented-programming/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>From Vim to TextMate</title>
		<link>http://cosine.org/2007/08/25/vim-textmate/</link>
		<comments>http://cosine.org/2007/08/25/vim-textmate/#comments</comments>
		<pubDate>Sat, 25 Aug 2007 12:00:46 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/08/25/vim-textmate/</guid>
		<description><![CDATA[Yesterday I switched from using Vim for all my code editing to TextMate. It is Mac only and costs &#8364;39 when I decide to register, but I really like how much easier it is to switch between more than two files and how it auto-terminates parentheses, logical statements, and HTML tags. This latter behavior should [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday I switched from using <a href="http://www.vim.org/">Vim</a> for all my code editing to <a href="http://macromates.com/">TextMate</a>.  It is Mac only and costs &euro;39 when I decide to register, but I really like how much easier it is to switch between more than two files and how it auto-terminates parentheses, logical statements, and HTML tags.  This latter behavior should be possible in Vim, but I had never found a plug-in or information on how.</p>
<p>I also looked at <a href="http://www.eclipse.org/">Eclipse</a>, but it has not grown on me nearly as fast.  In fact, at the risk of sounding like an Eclipse basher, I must say the interface is non-intuitive and the help files address every subject under the sun and the moon except how to make Eclipse useful.  I am sure that under all that non-intuitiveness and bad documentation is an excellent product, but I will not invest that much time to find it (yet) with TextMate already paying me back handsomely for only ten minutes of my time to install it and configure my preferences.  One might say this is the difference between a text editor and a full IDE&mdash;that may be true to some degree&mdash;but I think it is also the difference between a good user interface and just an interface.</p>
<p>I gave <a href="http://www.netbeans.org/">NetBeans</a> a test drive as well.  Let us just say that Eclipse, at least, did not get moved to my Trash and has no plans of visiting, either.  I may not have learned to like Eclipse, but I also still see value in learning more about it.  In a way I hope I am wrong about NetBeans, but it gets to wait a while before getting another shot.</p>
<p>So why did I do all this?  To write code faster!  I love Vim and the vi interface, but I like trying new things.  I might switch back after a few months if I can find out how to obtain what I like about TextMate in Vim.  Being rather extendable, Vim is capable of much more than I have demanded of it.  However, the main point is that it is important to me to try out new things periodically, or else I will never learn of the coolest new things (like I did when I learned Ruby in 2001).  I also periodically revisit things, such as Emacs about 18 months ago.  I did not switch, but getting reacquainted with it eight years after my last time seriously using it was fun.</p>
<p>I like to encourage everyone to pick up new things every once in a while.  Do not settle in a groove and stay there for the rest of your life.  Mix things up a little!  If you do not like your new adventure after a few days or weeks, you can always switch back!  It is fun, and may be profitable, too.  Of course, if you are the kind of person reading this, you probably already do this.  Carry on!</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/08/25/vim-textmate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why Use a Language-Powered Domain Specific Language?</title>
		<link>http://cosine.org/2007/08/16/languagepowered-domain-specific-language/</link>
		<comments>http://cosine.org/2007/08/16/languagepowered-domain-specific-language/#comments</comments>
		<pubDate>Thu, 16 Aug 2007 12:00:34 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/08/16/languagepowered-domain-specific-language/</guid>
		<description><![CDATA[Following my previous post on Domain Specific Languages (DSL), I had the pleasure of reading some responses. Aristotle does not like using eval (source): I mean, evaluating another source file every time you instantiate an object in that class? Awesome! If I had to maintain his code I&#8217;d refactor that part out of existence with [...]]]></description>
			<content:encoded><![CDATA[<p>Following <a href="http://www.cosine.org/2007/08/05/domain-specific-languages/">my previous post on Domain Specific Languages</a> (DSL), I had the pleasure of reading some responses.</p>
<p><a href="http://use.perl.org/~Aristotle/">Aristotle</a> does not like using eval (<a href="http://use.perl.org/~Aristotle/journal/34004">source</a>):</p>
<blockquote><p>I mean, evaluating another source file every time you instantiate an object in that class? Awesome! If I had to maintain his code I&#8217;d refactor that part out of existence <em>with a quickness</em>!</p></blockquote>
<p><a href="http://use.perl.org/~Ovid/">Ovid</a> agrees but is a bit more thoughtful and <a href="http://use.perl.org/~Ovid/journal/34010">explains DSLs better than I did</a>, except we differ in opinion regarding use of eval.  Ovid&#8217;s most important point is that DSLs can also be implemented by coding your own lexer and parser instead of using eval.  I did fail to mention that, but I think it lends yet more credence to my previous assertion:  that Ruby has better support for DSLs than Perl.  Otherwise, the Perl crowd would not be so much against using eval (on strings) instead of writing the parser.</p>
<p>What a pity!  There are certainly instances where eval is used in a sloppy and careless manner, but proper use to facilitate DSLs transcend that.  My use of eval in DSLs may not always be the best, but I am convinced eval is a useful tool that should not be so summarily dismissed because of its dirty infancy and that its bathwater got a bit grimy.</p>
<p><span id="more-21"></span>Where there is disagreement is that Rubyists often use language-powered DSLs in configuration files.  The closest I have ever seen in Perl was a configuration file made up of a large number of variable assignments.  The programmer simply did not want to deal with a parser to handle the hundreds of variables being assigned and all of the string variations that might be encountered, so he had them directly evaled from configuration.  Is that bad programming?  Maybe so in Perl terms, but one cannot ignore the benefits he realized without any loss of maintainability of his code:</p>
<ul>
<li>He avoided needing to invent a configuration file format.  Perl defined all the syntax for him.</li>
<li>He avoided needing to write a parser that would need to understand his assignments to various scalar, array, and hash values.</li>
<li>He did not need to figure out how to parse strings with special characters, such as quotes, so his strings could automatically accomodate arbitrary data as needed by administrators of the application.</li>
<li>He got clean handling of line breaks and multi-line statements for free.</li>
<li>He could make use of already assigned values to be included into other values without having to form his own string substitution symtax.</li>
<li>Comments and their syntax are included in the benefits.</li>
</ul>
<p>You automatically win all this when your configuration file is nothing more than <em>assignments</em>.  Ruby programmers take it farther and gain even more leverage by providing methods for use in configuration.</p>
<p>I have a hard time believing that an application having to provide its own code to deal with the above instead of just letting the language handle it is going to be easier to maintain, as is opined by the Perl users I quoted.  I am particularly convinced of it because I have myself written programs of both categories: those that use the power of the language in a DSL and those that carry along its own parser, defining its own syntax and language.  I suspect the reason many Perl enthusiasts do not agree is that they have never written a language-powered DSL in an appropriate situation.  If the most vocal Perl users (and their leadership, too?) is lambasting the idea, they certainly have no small social obstacle to get around if they honestly think the language-powered DSL is the right way to go.</p>
<p>With language-powered DSLs I have written a simple vulnerability scanner in 75 lines of Ruby.  The configuration file to check one specific vulnerability I needed checked was 30 lines.  105 lines of code to check one vulnerability is no big deal, but the program is vulnerability agnostic.  The configuration file only takes a port, information on what to spew to that port, and what to expect back from the system if it is vulnerable or not vulnerable.  It is already sophisticated enough to handle a multi-part conversation.  I believe the Perl community&#8217;s recommended way to do this with about the same amount of code would be to have modules instead of configuration files for each vulnerability.  With a DSL I do not have to mess with package overhead or making sure my @INC array will contain the directory with my vulnerability information.</p>
<p>I have also written a fetchmail/procmail hybrid in 512 lines of Ruby.  I needed something that could log into a POP server and download my mail like fetchmail does but also review the contents of the message and make procmail-like decisions about delivery before deciding to delete or keep the message on the server (the knowing to keep or delete being the key to why I could not use fetchmail and procmail).  My personal configuration file for this is about 60 lines, but there is no reason you would need more than 5 if you wanted very basic functionality.  I plan to share this program in the future, and I would be happy to speed that along if enough people show interest.</p>
<p>What did I gain, in addition to the benefits I noted above, in my DSL for the fetchmail/procmail hybrid?</p>
<ul>
<li>No need to decide on how to implement if, while, and other loop constructs.  Since this program has to make decisions it can make use of these constructs if the user desires to use them.</li>
<li>More elegant constructs specific to the task at hand.  These are methods defined that (usually) expect blocks of code that are run conditionally (and possibly multiple times) based on the needs of the application.</li>
<li>Users could assign different values to a configuration directive based on what host they are running from.  I found this feature useful in my personal configuration; I can have mail delivered locally if I am on my Linux host but delivered onto a network drive if I am using my Windows host.  This kind of feature is technically available even when you are limited to variable assignment, but I encourage its use when appropriate.</li>
</ul>
<p>Do not use language-powered DSLs when writing a parser is clearly superior, such as when the input cannot be trusted.  You cannot give the full power of the language to untrusted input unless you want a security nightmare.  As I stated above, I have written my own special use language from Ruby in order to parse code from untrusted sources.  I had to handle all the issues I mentioned above: dealing with the conditional and looping constructs, parsing strings that accommodate arbitrary data (through escape sequences), handling the parsing of arithmetic operators so they can be used inline, etc.  It was a full language executed inside my application.  So I do know what kind of code that entails, and it is most certainly not more maintainable than using the power of the language in your DSL.</p>
<p>If you have been told in the past by experts that &#8220;eval is bad&#8221; then I urge you to open your mind a little.  Listen to what they have to say about it&mdash;they do make some valid points about when <em>not</em> to use eval, but do not think it means that one should <em>never</em> use it.  I used to be in your camp, too, but when faced (in my case directly faced) with obvious benefit after obvious benefit, I came around. <img src='http://cosine.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   I urge you to take the plunge, too.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/08/16/languagepowered-domain-specific-language/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Parsing Dates in Unix with Ruby</title>
		<link>http://cosine.org/2007/08/11/parsing-dates-unix-ruby/</link>
		<comments>http://cosine.org/2007/08/11/parsing-dates-unix-ruby/#comments</comments>
		<pubDate>Sat, 11 Aug 2007 06:48:32 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/08/11/parsing-dates-unix-ruby/</guid>
		<description><![CDATA[Ever need to write a script that can read a human readable date and turn it into something a computer can use? How often do you have &#8220;August 10, 2007&#8243; in a string and need that converted to a number of seconds since January 1, 1970? As it turns out, Ruby includes an excellent module [...]]]></description>
			<content:encoded><![CDATA[<p>Ever need to write a script that can read a human readable date and turn it into something a computer can use?  How often do you have &#8220;August 10, 2007&#8243; in a string and need that converted to a number of seconds since January 1, 1970?</p>
<p>As it turns out, Ruby includes an excellent module for parsing dates.  It can handle several common formats, too!  All you need to do is require &#8216;parsedate&#8217; and you have access to it:</p>
<p><span id="more-17"></span>(Text in bold is what <em>you</em> would type.)</p>
<pre>
require &#39;parsedate&#39;
user_input = ARGF.readline
seconds = Time.local(*ParseDate.parsedate(user_input)).to_i
puts seconds

% <b>ruby parsedate_example</b>
<b>August 10, 2007</b>
1186722000
</pre>
<p>If you are in a hurry, try a one-liner:</p>
<pre>
% <b>ruby -rparsedate -nle &#92;
      &#39;print Time.local(*ParseDate.parsedate($_)).to_i&#39;</b>
<b>August 10, 2007</b>
1186722000
<b>2006-09-21</b>
1158814800
<b>2001 sep 8</b>
999925200
</pre>
<p>If you deal with <code>/etc/shadow</code> a lot you will find this useful for figuring out what today is in terms of the password last changed field by dividing the given number by 86400 (the number of seconds in each day):</p>
<pre>
% <b>ruby -rparsedate -nle &#92;
      &#39;print Time.local(*ParseDate.parsedate($_)).to_i / 86400&#39;</b>
<b>August 10, 2007</b>
13735
</pre>
<p>Or do it in reverse with Time.at:</p>
<pre>
% <b>env TZ=GMT ruby -nle &#39;print Time.at($_.to_i * 86400)&#39;</b>
<b>13735</b>
Fri Aug 10 00:00:00 +0000 2007
</pre>
<p>With Ruby you never need to venture far to manage your dates!  Let me know if you find this useful or if you have questions about similar should-be-easy problems you encounter!</p>
<p><!-- adman --></p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/08/11/parsing-dates-unix-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Security of Ruby&#8217;s Kernel#rand</title>
		<link>http://cosine.org/2007/08/07/security-ruby-kernel-rand/</link>
		<comments>http://cosine.org/2007/08/07/security-ruby-kernel-rand/#comments</comments>
		<pubDate>Wed, 08 Aug 2007 02:07:05 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/08/07/security-ruby-kernel-rand/</guid>
		<description><![CDATA[Last night I was at the Chicago Area Ruby Group, and there was a presentation by Trevor Turk on his El Dorado project. While he was showing us the code I saw the method that generates the application&#8217;s authentication token. I could not help but notice that the security of the authentication tokens depends greatly [...]]]></description>
			<content:encoded><![CDATA[<p>Last night I was at the <a href="http://www.chirb.org/">Chicago Area Ruby Group</a>, and there was a presentation by <a href="http://almosteffortless.com/">Trevor Turk</a> on his <a href="http://code.google.com/p/eldorado/source">El Dorado</a> project.  While he was showing us the code I saw the method that generates the application&#8217;s authentication token.  I could not help but notice that the security of the authentication tokens depends greatly on the security of Ruby&#8217;s Kernel#rand method.  Traditionally default rand functions are a bit light on security, and so I wondered if that was also true of Ruby&#8217;s Kernel#rand.</p>
<p>Only one way to find out!  I downloaded a fresh copy of the source code for Ruby 1.8.6 and started poking around in random.c, where the function in question lives.  My findings are mixed, and I have good news and bad news to report!</p>
<p><span id="more-16"></span>The good news is that if the Unix character device /dev/urandom is available then the random number generator is seeded with a value based from a read from that device.  The /dev/urandom device is a &#8220;secure&#8221; pseudo-random number generator device, so the resulting random numbers are going to be pretty good.  Note that you are still at the mercy of how well your operating system implements the algorithm for /dev/urandom and how <em>that</em> number generator gets seeded, but generally it works pretty well.</p>
<p>The bad news is that if /dev/urandom does not exist then your random numbers come from a podge of the current time, process id, and a sequence.  That will get you a random number good enough for shuffling your deck of cards in a friendly game of Euchre, but you do not want to depend on it for your bank account&#8217;s security.</p>
<p>Should you use Kernel#rand on a system without /dev/urandom?  That depends.  How secure do you want your application to be?  If there is any level of money or privacy involved, then I think you better make sure Ruby can find your /dev/urandom device.  You also better verify that your operating system&#8217;s /dev/urandom algorithm is implemented well.</p>
<p>What if there are large amounts of money involved?  All I have spoken of so far is the security of the seed to the random number generator.  How good is the random number generator itself?  For high security applications, does it matter how good our seed value is if we fail to use a good algorithm to crunch it?</p>
<p>Once again there is good news and bad news on that front.  Ruby uses the <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">Mersenne Twister</a> random number algorithm developed in 1997 by Makoto Matsumoto.  Wouldn&#8217;t you know it that a Japanese algorithm is in use in a programming language from the same islands? <img src='http://cosine.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />   The bad news is that it is not an algorithm that is naturally suited for secure applications&mdash;speed of number generation is its primary focus.  After being seeded the number generator will fall into a pattern.  The good news is that you need to generate lots of numbers before that pattern emerges, and it turns out that it can be used in secure applications with some limitations.  Please note that I am not a cryptographer, so I am gleaning this information from an external <a href="http://en.wikipedia.org/wiki/Mersenne_twister">source</a> or <a href="http://www.quadibloc.com/crypto/co4814.htm">two</a>.  Use it at your own risk.</p>
<p>But before you run out and use Kernel#rand on your new banking application, heed one more note of caution.  High security applications should not be depending on /dev/urandom for seeding another random number generator.  If you are going to be feeding a random number generator, why not get a real random number?  Systems that have /dev/urandom also have a /dev/random.  This latter device generates random numbers that do not get filtered through a random number generator.  Assuming your system has a good means of obtaining random bits to regurgitate to /dev/random and your application does not consume them too quickly (reads on /dev/random will block if it runs out of bits), you should seed your random number generator directly from /dev/random for your highest security applications.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/08/07/security-ruby-kernel-rand/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Domain Specific Languages</title>
		<link>http://cosine.org/2007/08/05/domain-specific-languages/</link>
		<comments>http://cosine.org/2007/08/05/domain-specific-languages/#comments</comments>
		<pubDate>Sun, 05 Aug 2007 17:41:49 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/08/05/domain-specific-languages/</guid>
		<description><![CDATA[I found out Friday night that chromatic from the Perl community has been writing about my previous posts: Cosine, if you post yet another followup, please explain precisely what in the world you possibly mean by &#8220;better support DSLs&#8221; and perhaps even &#8220;DSL&#8221; in general. Excellent comment, so I will. It goes somewhat to the [...]]]></description>
			<content:encoded><![CDATA[<p>I found out Friday night that <a href="http://use.perl.org/~chromatic/">chromatic</a> from the Perl community has <a href="http://use.perl.org/~chromatic/journal/33898">been writing</a> about my previous posts:</p>
<blockquote><p>Cosine, if you post yet another followup, please explain precisely what in the world you possibly mean by &#8220;better support DSLs&#8221; and perhaps even &#8220;DSL&#8221; in general.</p></blockquote>
<p>Excellent comment, so I will.  It goes somewhat to the Lisp idea that code <em>is</em> data, and that data <em>are</em> code.  When everything has parentheses around it, that concept is slightly more obvious because they look identical.  Here is some code:</p>
<p><code>(car mylist)</code></p>
<p>And here are some data:</p>
<p><code>'(car truck van)</code></p>
<p><span id="more-15"></span>So in Lisp if your list contains symbols that map to function and variable names then you can do an eval and execute your data as code.  So one nice thing to do in any language that has an eval function, Perl and Ruby included, is to sometimes have &#8220;data&#8221; that are run through eval and executed to provide configuration or additional functionality:</p>
<pre>
do_stuff {
    print "hello world&#92;n";
}
</pre>
<p><!-- adman --></p>
<p>If the right context is created, the above code executes in that context (this example works for both Ruby and Perl due to their similarities), and it provides a powerful way to write small programs with extremely powerful configuration options because the whole force of the underlying programming language is available.  The resulting &#8220;configuration file language&#8221; we create in this process is the DSL.</p>
<p>Let us see what the &#8220;hello world&#8221; example of a DSL looks like.  We will use the <a href="/ex/2007/08/05/domain-specific-languages/config">above example</a> as our DSL.  This DSL defines a do_stuff function that will save the block of code to be executed later.  This example will execute the code in the above file just once.</p>
<p>In Ruby (<a href="/ex/2007/08/05/domain-specific-languages/code.rb">download</a>):</p>
<pre>
class DoStuff
  def initialize
    instance_eval File.read('config')
  end

  def do_stuff (&amp;block)
    @do_stuff = block
  end

  def run_func
    @do_stuff.call
  end
end

a = DoStuff.new
a.run_func
</pre>
<p>In Perl (<a href="/ex/2007/08/05/domain-specific-languages/code.pl">download</a>):</p>
<pre>
package DoStuff;

our $current_self = undef;

sub new {
  my ($class) = @_;
  my $self = $current_self = {};
  bless $self, $class;
  open CONFIG, "&lt;config";
  my @config = &lt;CONFIG&gt;;
  close CONFIG;
  eval join('', @config);
  $current_self = undef;
  return $self;
}

sub do_stuff (&amp;) {
  my ($func) = @_;
  $current_self-&gt;{'do_stuff'} = $func;
}

sub run_func {
  my ($self) = @_;
  &amp;{$self-&gt;{'do_stuff'}};
}

package main;

my $a = DoStuff-&gt;new();
$a-&gt;run_func();
</pre>
<p>The reason I feel that Ruby supports this better than Perl is twofold:</p>
<ol>
<li>Ruby has contextual eval statements, whereas Perl has just one eval statement that loses context (this can be seen by use of <code>$current_self</code> above to work around the problem); and</li>
<li>Ruby&#8217;s syntax allows for cleaner and more readable DSLs.</li>
</ol>
<p>Addressing #2 above, if you want a function in your DSL to take arguments <em>and</em> a block of code, then in Ruby you have:</p>
<p><code>do_stuff(1, 2, 3) { ... #this code might be long }</code></p>
<p>In Perl the arguments go at the tail of the code (unless you make the code reference explicit):</p>
<p><code>do_stuff { ... #this code might be long } (1, 2, 3);</code></p>
<p>If you are reading code in a Perl-based DSL, by the time you get to the end of a block of code and see the arguments for the functions, you may not recall which function it is associated with (unless you bounce back and forth on those curly braces). The arguments are generally used to modify the basic functionality of the function and are easy to comprehend when at the top of the invocation:</p>
<p><code>do_stuff(:silently, :with => :things, :notify => "matz") { ... }</code></p>
<p>Anyway, certainly there are Perl enthusiasts out there that will disagree with these opinions.  Maybe there is some aspect of Perl I do not understand that makes it easier than I thought in Perl, and if so I would love to know.  I still have to <a href="/2007/07/20/perl/">use Perl</a> occasionally and so any advancement of that knowledge is useful, too. <img src='http://cosine.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   And actually, even though I still find it much easier to write DSLs in Ruby than in Perl, in writing this post&#8217;s examples I discovered that writing a DSL in Perl was a lot easier than I thought it was.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/08/05/domain-specific-languages/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Knowing Ruby and Perl</title>
		<link>http://cosine.org/2007/07/24/knowing-ruby-perl/</link>
		<comments>http://cosine.org/2007/07/24/knowing-ruby-perl/#comments</comments>
		<pubDate>Wed, 25 Jul 2007 01:51:56 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/07/24/knowing-ruby-perl/</guid>
		<description><![CDATA[I came upon a startling realization today after reading some feedback from an anonymous source regarding my previous post: Your complaint about being unable to write code the way you&#8217;re used to with Ruby when picking up Perl for a hours seemed pretty thoughtless. Of course it&#8217;s harder for you in Perl &#8212; you don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>I came upon a startling realization today after reading some feedback from an anonymous source regarding my previous post:</p>
<blockquote><p>Your complaint about being unable to write code the way you&#8217;re used to with Ruby when picking up Perl for a hours seemed pretty thoughtless. Of course it&#8217;s harder for you in Perl &#8212; you don&#8217;t know Perl nearly as well as you know Ruby! Claiming that this is somehow a fundamental flaw of Perl is just not right.</p></blockquote>
<p>I meant to suggest in my previous post that the flaw was in <em>me</em> for no longer thinking in Perl when using Perl, though at the same time if Perl were to better support DSLs (domain specific languages) then I would have gotten a Get-Out-of-Jail-Free Card despite my mis-think.  I hope that others reading this benefit from the clarification as well.</p>
<p><span id="more-10"></span>But this reply also made me think about my comparative knowledge in the two languages.  Do I really know Ruby better than Perl like stated in the feedback?  I do not feel like I do.  I know <em>a lot</em> about both languages, and there are gaps in my knowledge of each language.  In fact, other than those people that write Perl modules in C, I generally know as much or more about Perl than other Perl users I meet.  It is a real nice language that has served me very well over the years.  My problem with it is that I just do not alter my thinking to eliminate concepts alien to Perl when using it, or at least not in version one of whatever I am writing. <img src='http://cosine.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><!-- adman --></p>
<p>My knowledge of Ruby is not shallow, but it is not as deep as I would really like, either.  I can write Ruby modules in C, and I have used that knowledge to embed Ruby directly into a monolithic C program in an attempt to port it slowly, release by release.  However, there are constantly things that crop up in Ruby that leave me scratching my head thinking, &#8220;wow, I can do that!?&#8221;  I did not know until recently that a Hash object could be given a default value other than nil.  Previously, if were using a Hash of Array objects I would have done this:</p>
<pre>
def my_set (hash, key, index, object)
    if not hash.has_key? key
        hash[key] = Array.new
    end
    hash[key][index] = object
end

h = Hash.new
my_set(h, 'red', 1, 'one')
my_set(h, 'blue', 2, 'two')
p h
=&gt; {"blue"=&gt;[nil, nil, "two"], "red"=&gt;[nil, "one"]}
</pre>
<p>Now I know can just define the Hash object differently to do the same thing:</p>
<pre>
h = Hash.new { |hash, key| hash[key] = Array.new }
h['red'][1] = 'one'
h['blue'][2] = 'two'
p h
=&gt; {"blue"=&gt;[nil, nil, "two"], "red"=&gt;[nil, "one"]}
</pre>
<p>It is pretty simple and makes for cleaner code, but I did not know it.  I must not have paid enough attention during the Hash class. <img src='http://cosine.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Little things like this led me to think that perhaps I know Perl better than Ruby, but I think that is probably not true anymore.  There is so much to know about both languages that one can easily not be certain, but since 2004 I have not been paying nearly as much attention to Perl as I have to Ruby.  Over the course of these last three years it must be inevitable that my Ruby knowledge would surpass my Perl knowledge.  I think it has happened, but I would never wager a bet on when.  I just do not know.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/07/24/knowing-ruby-perl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Back to Perl</title>
		<link>http://cosine.org/2007/07/20/perl/</link>
		<comments>http://cosine.org/2007/07/20/perl/#comments</comments>
		<pubDate>Fri, 20 Jul 2007 19:55:55 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/07/20/perl/</guid>
		<description><![CDATA[In my day job I spent a few hours today working in Perl. Having been using Ruby for over six years now I am quite familiar with how lacking Perl is in comparison. However, once again I was floored by how much less intuitive things are outside of Ruby. Even though Perl is a great [...]]]></description>
			<content:encoded><![CDATA[<p>In my day job I spent a few hours today working in Perl.  Having been using Ruby for over six years now I am quite familiar with how lacking Perl is in comparison.  However, once again I was floored by how much less intuitive things are outside of Ruby.  Even though Perl is a great language, having tasted from much better nectar makes it harder to appreciate those great strides Larry Wall made in the language.</p>
<p>What kind of things were not so intuitive?  In my program today I had a situation where some questions need to be asked of the user.  I wanted to use a DSL (domain specific language) to handle the querying because I need to create about a dozen similar programs that all do things just a bit differently.  To facilitate this I abstracted as much common code as possible into its own class, threw it into a Perl module file, and made it available for all the programs to use.</p>
<p><span id="more-9"></span> However, Perl is not really capable of DSLs, and trying just made the code really messy.  As it stands I have something that works but will need some revision next time I update it.  Instead of a clean DSL I have a strange function-passing call-back situation that makes following the code more challenging than such a small program should be.  In Ruby this thought would have led to clean code, but in Perl I need to revisit the code and rework it to a pure object-oriented design, sans psuedo-DSL, to effect more maintainable code.  At the same time, without being able to think in terms of the DSL will make writing the dozen or so programs that are really the point of this whole exercise more difficult.</p>
<p>If you want to help save me from this situation in the future, go out there and help make Ruby more mainstream.  I am only stuck using Perl because it comes with everything.  It comes pre-installed with almost every Unix now, and often it comes packaged again with third-party applications.  Ruby should be in many of these positions.  Ruby comes with Mac OS X, but not much else.  Until the day I hear Ruby comes pre-installed with Solaris I know that Ruby has not yet really broken into the mainstreamâ€”what Sun includes with Solaris is a good indication of what is in mainstream use.</p>
<p>So come on!  Let us get out there and promote Ruby!  Let us bring Ruby into the mainstream and make everyone&#8217;s lives easier!</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/07/20/perl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Capistrano and Administration</title>
		<link>http://cosine.org/2007/07/18/capistrano-administration/</link>
		<comments>http://cosine.org/2007/07/18/capistrano-administration/#comments</comments>
		<pubDate>Wed, 18 Jul 2007 23:00:41 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://www.cosine.org/2007/07/18/capistrano-evolution/</guid>
		<description><![CDATA[Know what Capistrano is? I did a presentation on it in February, so I know a little about it. At the time I was investigating it as a hopeful candidate that could assist with configuration management for general systems administration for an environment of about 150 Solaris systems. I discovered that Capistrano is a fantastic [...]]]></description>
			<content:encoded><![CDATA[<p>Know what Capistrano is?  I did a <a href="http://www.cosinewave.net/ruby/cap" title="Using Capistrano">presentation</a> on it in February, so I know a little about it.  At the time I was investigating it as a hopeful candidate that could assist with configuration management for general systems administration for an environment of about 150 Solaris systems.  I discovered that Capistrano is a fantastic program and a great tool for application deployment.  Honestly there is no reason you should ever put up with the act of moving an application to production being more than a few keystrokes, and using Capistrano makes that possible.  However, Capistrano was unable to help out such a large Unix environment.</p>
<p>Capistrano has no facility for continuing tasks upon failure.  In a large Unix environment, stuff needs to happen even if only 98% of the systems are up.  What about the 2% not available?  They can get the update later when they&#8217;re back.  We needed a tool that can just do the work and get it done on the 98% and report on who failed.  Later, when the failed systems are back online, the tool should automatically update them on the next run.  Then we can go about fixing the issues causing those 2% of systems to fail and rest assured that all our changes will be pushed soon.</p>
<p><span id="more-7"></span> I intend to fill this gap.  Jamis Buck, the maintainer of Capistrano, also wrote the Net::SSH module for Ruby.  It is a spectacular module.  With it, I plan to write an agentless tool that runs from a central server and uses SSH to log into each system for whatever task necessary.  Couple it with some tools to manage users, groups, system configurations, and software installations, and a new tool to conquer the world will be born.</p>
<p>If you want to conquer the world with me, let me know! <img src='http://cosine.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>I have written a similar tool before.  Back when I worked at Abbott I wrote a little tool we called confmgt.  I used Perl because when I started the project around 1999 or 2000 that was the best language I knew.  Additionally, Perl was installed on every Research and Development Unix system in the company, so I could count on it being present.  The original version ran on a central server and used rdist to push files to target hosts after performing some non-trivial logic on which files to include in and exclude from the transfer.</p>
<p>Eventually the tool grew and features were added, and by version 3.0 (the last major version when I left Abbott) the program used rsync by default and could be run either from central server or from the host being updated.  More complicated configurations required features to include more customization in how distribution areas were laid out.  Despite still being written in Perl, I was very proud of the 3.0 release of confmgt.  It was a masterpiece of Perl and of programming in general.  With this release other Unix administrators were no longer coming to me and asking for new features; instead they came, asked, and then left knowing how to do what they were requesting.  I have rarely felt greater pride in my work.</p>
<p>So now I am going to repeat myself, but this time in Ruby.  Instead of rsync I will use Net::SFTP.  The configuration file will likely be similar to Capistrano&#8217;s so that people familiar with one can use the other easily (as it should be!).  It is time to change the world.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/07/18/capistrano-administration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby, Rails, Applicaton Security, and more!</title>
		<link>http://cosine.org/2007/06/20/ruby-rails-applicaton-security/</link>
		<comments>http://cosine.org/2007/06/20/ruby-rails-applicaton-security/#comments</comments>
		<pubDate>Thu, 21 Jun 2007 03:28:01 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Website]]></category>

		<guid isPermaLink="false">http://www.cosine.org/musings/2007/06/23/ruby-rails-applicaton-security-and-more/</guid>
		<description><![CDATA[I&#8217;ve decided that cosine.org should be dedicated to my favorite computer topics: Ruby, Rails, application security, and OpenBSD. This is all awesome stuff. Stuff that is awesomely interesting to me. However my level of knowledge in these topics varies a bit, and it creates a perplexing situation for me. Firstly, my recent computer research efforts [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve decided that cosine.org should be dedicated to my favorite computer topics:  Ruby, Rails, application security, and OpenBSD.  This is all awesome stuff.  Stuff that is awesomely interesting to me. However my level of knowledge in these topics varies a bit, and it creates a perplexing situation for me.</p>
<p><span id="more-6"></span> Firstly, my recent computer research efforts have been to learn yet more about application security.  I know what I know very well, but I also know when I feel a weakness in my knowledgeâ€”and I <em>need</em> to do more with application security to advance my knowledge there.  I have all the basics now; the next step is application.</p>
<p>Additionally, I need to do more with Rails.  I know Ruby very well, and it is absolutely the best programming language I have ever used. I have dabbled with Rails know the basics, but I need to do something useful with it so I have an ongoing Rails project to care for.  Without something like that my knowledge in Rails has not broken a mediocre level, and I have fallen behind in recent advances that the Rails core team has delivered recently.  An update to this very website into a Rails powered site is very likely! <img src='http://cosine.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>In summary, the two areas I want to target my development is application security and Rails.  Tune in to see what I decide to do with each of these.  Drop me a line if you want to chat about it!  I love talking about these subjects, so I will love to talk.</p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2007/06/20/ruby-rails-applicaton-security/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Updating Webpage</title>
		<link>http://cosine.org/2006/09/27/updating-webpage/</link>
		<comments>http://cosine.org/2006/09/27/updating-webpage/#comments</comments>
		<pubDate>Wed, 27 Sep 2006 06:15:54 +0000</pubDate>
		<dc:creator>Cosine Jeremiah</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Website]]></category>

		<guid isPermaLink="false">http://www.cosine.org/musings/2007/06/23/updating-webpage/</guid>
		<description><![CDATA[If it isn&#8217;t obvious, I&#8217;m updating my web page for the first time in over four years. This is mostly due to the fact that I&#8217;ve been participating in the LiveJournal community for the most part, and blogging there. There&#8217;s also a link in the sidebar. I still want to use cosine.org for some stuff, [...]]]></description>
			<content:encoded><![CDATA[<p>If it isn&#8217;t obvious, I&#8217;m updating my web page for the first time in over four years.  This is mostly due to the fact that I&#8217;ve been participating in the <a href="http://www.livejournal.com/">LiveJournal</a> community for the most part, and blogging <a href="http://cosinejeremiah.livejournal.com/">there</a>.  There&#8217;s also a link in the sidebar.</p>
<p><span id="more-5"></span> I still want to use cosine.org for some stuff, but I&#8217;m not sure how I&#8217;m going to manage it yet.  It would be a good place for a technical blog, but so would <a href="http://www.cosinewave.net/">cosinewave.net</a> along with the comic.  Decisions!</p>
<p>Right now cosine.org is all static content.  That&#8217;s not ideal for a blog, where comments are nifty.  So something&#8217;s going to have to give. I&#8217;d write a small Rails app for the task, but the site I&#8217;m hosting on is too low on RAM to handle even one Rails application except using the CGI gateway (slooow!).</p>
<p>And by the way, although I&#8217;ve been saying it out loud for five years, I&#8217;ll say it again right here:  If you program and you haven&#8217;t looked at <a href="http://www.ruby-lang.org/">Ruby</a> yet, you will kick yourself when you do someday and wonder why you didn&#8217;t check it out sooner.  So just check it out, okay?  No, just knowing Python is <em>not</em> sufficient.  Ruby <em>is</em> a cut above.  I&#8217;ve been saying this for five years, but I&#8217;m not good at sales.  Ruby will speak for itself when you learn it, okay?  <em>Trust me!</em></p>
<p>And if I end up being a big fat liar with my pants on fire about this Ruby stuff, you probably didn&#8217;t lose much time figuring it out, did you? Oh, you haven&#8217;t looked at Ruby yet?  Dammit, <em><a href="http://www.ruby-lang.org/">GO LOOK NOW</a>!</em></p>
]]></content:encoded>
			<wfw:commentRss>http://cosine.org/2006/09/27/updating-webpage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

