<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>philcrissman.com</title>
  <id>philcrissman.com</id>
  <updated>2010-08-11T00:00:00-07:00</updated>
  <author>
    <name></name>
  </author>
  <entry>
    <title>Fun With The Major Scale</title>
    <link href="http://philcrissman.com/2010/08/11/fun-with-the-major-scale" rel="alternate"/>
    <id>http://philcrissman.com/2010/08/11/fun-with-the-major-scale</id>
    <published>2010-08-11T00:00:00-07:00</published>
    <updated>2010-08-11T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Got to chatting with Nate &lt;a href="http://twitter.com/fowlduck"&gt;(@fowlduck)&lt;/a&gt; about musical notation last night. He was pointing out that bits of the notation seem arbitrary and probably archaic, likening it to legacy code of a sort. For example, why no whole tone between B and C, E and F? This post is NOT meant to be a defense of music notation, a &amp;ldquo;setting straight&amp;rdquo; of anything, or even a definitive description of musical theory (at which I&amp;rsquo;m a rank amateur). It just got me thinking about the major scale and the circle of fourths &amp;amp; fifths, which led to some playing around on the command line, which led to this. Enjoy&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Got to chatting with Nate &lt;a href="http://twitter.com/fowlduck"&gt;(@fowlduck)&lt;/a&gt; about musical notation last night. He was pointing out that bits of the notation seem arbitrary and probably archaic, likening it to legacy code of a sort. For example, why no whole tone between B and C, E and F? This post is NOT meant to be a defense of music notation, a &amp;ldquo;setting straight&amp;rdquo; of anything, or even a definitive description of musical theory (at which I&amp;rsquo;m a rank amateur). It just got me thinking about the major scale and the circle of fourths &amp;amp; fifths, which led to some playing around on the command line, which led to this. Enjoy.&lt;/p&gt;

&lt;p&gt;The thing that makes it seem so strange is, at least in part, the major scale. The octave consists of twelve semi-tones, in which the major scale is set in this pattern: whole tone, whole tone, semitone, whole tone, whole tone, whole tone, whole tone, semi-tone. Like so:&lt;/p&gt;

&lt;pre&gt;
  1   2   3   4   5   6   7   8   9   10  11  12  13
| C |   | D |   | E | F |   | G |   | A |   | B | C | ... (etc) 
&lt;/pre&gt;


&lt;p&gt;The next root note (13th semi-tone, above) is only a semi-tone off from the last note of the scale. And so on. The semi-tone before or after any given note is a flat or a sharp respectively, giving rise to the B# == C, Cb == B, E# == F, Fb == E identities. So, let&amp;rsquo;s just accept the scale as a given; that this pattern of whole tones and semi-tones sounds pleasing to the ear.&lt;/p&gt;

&lt;p&gt;So why is it C that has all natural notes (no sharps or flats)? Good question. That part, to me at least, does seem arbitrary, but effectively it doesn&amp;rsquo;t matter. Given the above system, the major scale in one key and one key only will have no sharps or flats. But still, why structure the notes this way? It still doesn&amp;rsquo;t necessarily seem to make sense.&lt;/p&gt;

&lt;p&gt;There are a few reasons. For one, we want to be able to express every scale by naming off the notes, and we&amp;rsquo;d like each note to be a different letter. So we need 7 letters.&lt;/p&gt;

&lt;p&gt;Where it gets really interesting is the circle of fourths and fifths.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Circle_of_fifths_deluxe_4.svg/400px-Circle_of_fifths_deluxe_4.svg.png" /&gt;&lt;/p&gt;

&lt;p&gt;So, if you go around clockwise, you&amp;rsquo;re counting by fifths (G is the fifth note of the C major scale, D is the fifth note of the G major scale, etc) and if you go around counter-clockwise you&amp;rsquo;re counting by fourths (F is the fourth note of C, Bb is the fourth note of F, etc). If you go around clockwise, each scale has one additional sharped note until you get to 180 degrees around, then it has n-1 flat notes, and loses one flat each fifth till you get back to C (no sharps or flats); vis versa the other direction. This is actually really cool; each scale, in addition to being unique in that, well, it has a different root note, is unique in that it is the only scale to have its specific number of sharps or flats. If a scale has 3 sharps, it&amp;rsquo;s A. Period. There isn&amp;rsquo;t another choice. Neat!&lt;/p&gt;

&lt;p&gt;So for fun, we can explore the circle of fifths in the command line. First lets set it up:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&gt; circle = (0..11).map{|n| n*7%12 }
 =&gt; [0, 7, 2, 9, 4, 11, 6, 1, 8, 3, 10, 5] 
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Well. That doesn&amp;rsquo;t mean a whole lot. How can we map it to notes? Let&amp;rsquo;s just construct a reference array really quick. (I&amp;rsquo;m making it an instance variable so I can use it in a method later; this was all done in irb.)&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&gt; @notes = ["C", "C#/Db", "D", "D#/Eb", "E", "E#/F", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb", "B/Cb"]
 =&gt; ["C", "C#/Db", "D", "D#/Eb", "E", "E#/F", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb", "B/Cb"]
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So, to read our circle, we&amp;rsquo;d do:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&gt; circle.map{|n| @notes[n]}
 =&gt; ["C", "G", "D", "A", "E", "B/Cb", "F#/Gb", "C#/Db", "G#/Ab", "D#/Eb", "A#/Bb", "E#/F"]
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Hooray. The circle of fifths. Now, so what? Well, let&amp;rsquo;s make a little method to construct a major scale from the &lt;code&gt;@notes&lt;/code&gt; variable. We&amp;rsquo;ll take a root note as an argument, so we can construct any major scale we like.&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&gt; def major(root=0)
?&gt;  offset = (0..11).map{|n| @notes[(n+root)%12]}
?&gt;  [offset[0], offset[2], offset[4], offset[5], offset[7], offset[9], offset[11]].join(" ")
?&gt;  end
 =&gt; nil
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So, just calling &lt;code&gt;major&lt;/code&gt; with no arguments should give us the C major scale; calling with, say, 5 should give us F major (5 in this case is the index of F in @notes; but you were already following that, I know):&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&gt; major
 =&gt; "C D E E#/F G A B/Cb" 
&gt; major(5)
 =&gt; "E#/F G A A#/Bb C D E" 

&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So we said that the circle of fifths added a sharp each increment, and then flipped to flats and removed on each increment. Let&amp;rsquo;s watch it happen:&lt;/p&gt;

&lt;pre&gt;
&lt;code class=""&gt;
&gt;&gt; circle.each{|n| puts major(n) }
C D E F G A B
G A B C D E F#/Gb
D E F#/Gb G A B C#/Db
A B C#/Db D E F#/Gb G#/Ab
E F#/Gb G#/Ab A B C#/Db D#/Eb
B C#/Db D#/Eb E F#/Gb G#/Ab A#/Bb
F#/Gb G#/Ab A#/Bb B C#/Db D#/Eb F
C#/Db D#/Eb F F#/Gb G#/Ab A#/Bb C
G#/Ab A#/Bb C C#/Db D#/Eb F G
D#/Eb F G G#/Ab A#/Bb C D
A#/Bb C D D#/Eb F G A
F G A A#/Bb C D E
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Not as neat as it could look since I put the #/b both in the original notes array; the note you&amp;rsquo;d read would be the one with a consecutive letter after the previous note. So in G, the note following E is F#. In Eb, the note following G is Ab&amp;hellip; and so on. The same note &lt;em&gt;letter&lt;/em&gt; only appears once in any given scale. A sharp or flat is added or removed each increment you go around the circle.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t have any startling conclusions to close this off with. Just that music is pretty cool, and that a few of the things that &lt;em&gt;seem&lt;/em&gt; arbitrary just have to be that way &amp;mdash; assuming we&amp;rsquo;re going to base the system around 12 equally tempered semitones (see &lt;a href="http://en.wikipedia.org/wiki/Equal_temperament"&gt;Equal Temperment&lt;/a&gt;, or even &lt;a href="http://en.wikipedia.org/wiki/The_Well-Tempered_Clavier"&gt;Bach&amp;rsquo;s Well-Tempered Clavier&lt;/a&gt; (evidently there&amp;rsquo;s some dispute over whether or not Bach&amp;rsquo;s intended tuning was equal or, uh, &amp;ldquo;well&amp;rdquo; tempered; I was not aware of this!)) and a 7 note major scale &amp;mdash; neither of which are absolutely necessary, of course, and there are other ways to do it. See &lt;a href="http://en.wikipedia.org/wiki/Mathematics_of_musical_scales#Mathematics_of_musical_scales"&gt;Mathematics of musical scales&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Musical_tuning#Tuning_systems"&gt;tuning systems&lt;/a&gt; for more.&lt;/p&gt;

&lt;p&gt;Happy musicking.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Push it somewhere else</title>
    <link href="http://philcrissman.com/2010/08/06/push-it-somewhere-else" rel="alternate"/>
    <id>http://philcrissman.com/2010/08/06/push-it-somewhere-else</id>
    <published>2010-08-06T00:00:00-07:00</published>
    <updated>2010-08-06T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/patrick-make-a-gist.jpg" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;For all the folks in #rubyonrails, and beyond.&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/patrick-make-a-gist.jpg" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;For all the folks in #rubyonrails, and beyond.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>graffiti on a train</title>
    <link href="http://philcrissman.com/2010/08/04/graffiti-on-a-train" rel="alternate"/>
    <id>http://philcrissman.com/2010/08/04/graffiti-on-a-train</id>
    <published>2010-08-04T00:00:00-07:00</published>
    <updated>2010-08-04T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/hbak_graffiti.jpg" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;Pic taken along the trail on the way from Minneapolis to Hopkins.&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/hbak_graffiti.jpg" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;Pic taken along the trail on the way from Minneapolis to Hopkins.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>There Will Be No Newsletter</title>
    <link href="http://philcrissman.com/2010/08/03/there-will-be-no-newsletter" rel="alternate"/>
    <id>http://philcrissman.com/2010/08/03/there-will-be-no-newsletter</id>
    <published>2010-08-03T00:00:00-07:00</published>
    <updated>2010-08-03T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;So, a few weeks ago I saw &lt;a href="http://letter.ly"&gt;letter.ly&lt;/a&gt; and I thought, hey, there&amp;rsquo;s an idea, so I created an account and thought to myself, &lt;em&gt;what could I send out a newsletter about? I know, how about time management? I have to manage my own time, I get stuff done. That&amp;rsquo;s useful, right?&lt;/em&gt; And so I wrote a couple posts, debated on actually getting started. Yesterday I went ahead and pulled the trigger, send out the first one and also publicized it on twitter (to no real response, which is more or less as I expected)&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;So, a few weeks ago I saw &lt;a href="http://letter.ly"&gt;letter.ly&lt;/a&gt; and I thought, hey, there&amp;rsquo;s an idea, so I created an account and thought to myself, &lt;em&gt;what could I send out a newsletter about? I know, how about time management? I have to manage my own time, I get stuff done. That&amp;rsquo;s useful, right?&lt;/em&gt; And so I wrote a couple posts, debated on actually getting started. Yesterday I went ahead and pulled the trigger, send out the first one and also publicized it on twitter (to no real response, which is more or less as I expected).&lt;/p&gt;

&lt;p&gt;I started to reconsider almost right away. While I like writing, I&amp;rsquo;m not certain I want to make a job of it. And while I like time management, and I think I&amp;rsquo;m decent at it, it doesn&amp;rsquo;t really drive me to fits of enthusiasm as a topic. I&amp;rsquo;d probably be better off taking my top few time management ideas and making blog posts out of them than I would attempting to come up with something new every single week.&lt;/p&gt;

&lt;p&gt;The for-profit newsletter does seem like a good idea, but I think I&amp;rsquo;m going to stick with one channel of writing, for now. The blog has a couple ads on it, which I don&amp;rsquo;t apologize for (nor do I really care if you block ads; your prerogative), so I guess if whatever I write gets immense attention (not likely, but it&amp;rsquo;s happened a few times), some reward will trickle back.&lt;/p&gt;

&lt;p&gt;Now, an e-book of some sort does seem like a better idea, and I have several ideas (one of which might well have to do with time management) that I might try to eventually work on in that direction. But a newsletter; I don&amp;rsquo;t really think I want to pour my efforts into that, right now. I think they&amp;rsquo;re better placed elsewhere.&lt;/p&gt;

&lt;p&gt;So if you saw yesterday&amp;rsquo;s tweet about the experiment, and followed the link over to &lt;a href="http://letter.ly"&gt;letter.ly&lt;/a&gt;, yeah. That&amp;rsquo;s the backstory, and that&amp;rsquo;s why if you look for it now, you&amp;rsquo;ll see it has a message saying it&amp;rsquo;s &lt;em&gt;ceased&lt;/em&gt;. (UX note: could not find a way to actually &lt;em&gt;delete&lt;/em&gt; a newsletter. Seems like that would be a handy function.)&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>RVM</title>
    <link href="http://philcrissman.com/2010/07/29/rvm" rel="alternate"/>
    <id>http://philcrissman.com/2010/07/29/rvm</id>
    <published>2010-07-29T00:00:00-07:00</published>
    <updated>2010-07-29T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/rvm_image.png" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;I gave a short presentation on &lt;a href="http://rvm.beginrescueend.com"&gt;RVM&lt;/a&gt; on Monday at &lt;a href="http://ruby.mn"&gt;RUM&lt;/a&gt;&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/rvm_image.png" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;I gave a short presentation on &lt;a href="http://rvm.beginrescueend.com"&gt;RVM&lt;/a&gt; on Monday at &lt;a href="http://ruby.mn"&gt;RUM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The slides can be found at &lt;a href="http://rubymn-rvm.heroku.com"&gt;rubymn-rvm.heroku.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Faith</title>
    <link href="http://philcrissman.com/2010/07/28/faith" rel="alternate"/>
    <id>http://philcrissman.com/2010/07/28/faith</id>
    <published>2010-07-28T00:00:00-07:00</published>
    <updated>2010-07-28T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/vader_faith.jpg" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;I know, I know, the faux motivational poster is an old and tired &lt;a href="http://en.wikipedia.org/wiki/Meme"&gt;meme&lt;/a&gt;. Sorry.&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/vader_faith.jpg" width="440" /&gt;&lt;/p&gt;

&lt;p&gt;I know, I know, the faux motivational poster is an old and tired &lt;a href="http://en.wikipedia.org/wiki/Meme"&gt;meme&lt;/a&gt;. Sorry.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>I Write Like</title>
    <link href="http://philcrissman.com/2010/07/27/i-write-like" rel="alternate"/>
    <id>http://philcrissman.com/2010/07/27/i-write-like</id>
    <published>2010-07-27T00:00:00-07:00</published>
    <updated>2010-07-27T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;I&amp;rsquo;ve seen the &lt;a href="http://iwl.me/"&gt;I write like&lt;/a&gt; links show up on facebook and twitter a few times, so I decided I&amp;rsquo;d take a look. Not content to simply feed it one sample, I fed it the text from several of the posts from the archive. Here were the results:&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I&amp;rsquo;ve seen the &lt;a href="http://iwl.me/"&gt;I write like&lt;/a&gt; links show up on facebook and twitter a few times, so I decided I&amp;rsquo;d take a look. Not content to simply feed it one sample, I fed it the text from several of the posts from the archive. Here were the results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://philcrissman.com/2009/01/14/i-hold-strong-opinions-about-the-placement-of-curly-braces"&gt;I Hold Strong Opinions About The Placement Of Curly Braces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;=&gt; I write like: &lt;strong&gt;H.P. Lovecraft&lt;/strong&gt;. &lt;em&gt;Really? Wait&amp;hellip; what?&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://philcrissman.com/2010/02/16/no-were-not-the-stupid-ones"&gt;No, We&amp;rsquo;re Not The Stupid Ones&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://philcrissman.com/2009/01/16/in-which-i-am-no-longer-a-very-good-bachelor"&gt;In Which I Am No Longer A Very Good Bachelor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://philcrissman.com/2010/04/01/oracle-to-acquire-oracle"&gt;Oracle To Acquire Oracle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;=&gt; I write like: &lt;strong&gt;Cory Doctorow&lt;/strong&gt;. &lt;em&gt;Huh. You think? Well, okay. Thanks!&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://philcrissman.com/2006/09/22/the-emperors-new-web"&gt;The Emperor&amp;rsquo;s New Web&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;=&gt; I write like: &lt;strong&gt;Jonathan Swift&lt;/strong&gt;. &lt;em&gt;[blushing] No, no&amp;hellip; you&amp;rsquo;re too kind.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Not sure how they are analyzing the text and reaching their conclusions, but there&amp;rsquo;s at least a &lt;em&gt;little&lt;/em&gt; bit of smarts in there; that last one, the one which was compared to Swift, is indeed a satire, though I&amp;rsquo;m not going to claim it&amp;rsquo;s in the calibre of Swift&amp;rsquo;s satire, but still; their algorithm picked something out of it which prompted the comparison. Not bad.&lt;/p&gt;

&lt;p&gt;So, evidently, according to their analyses, I write most often like Cory Doctorow. I&amp;rsquo;ve only read &lt;em&gt;Down And Out In The Magic Kingdom&lt;/em&gt;, and several of his blog posts/essays, but enough to consider it a compliment, though I&amp;rsquo;m not certain it&amp;rsquo;s deserved. Regardless, there we have it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How Not To Write Sorting Algorithms in Ruby</title>
    <link href="http://philcrissman.com/2010/07/18/how-not-to-write-sorting-algorithms-in-ruby" rel="alternate"/>
    <id>http://philcrissman.com/2010/07/18/how-not-to-write-sorting-algorithms-in-ruby</id>
    <published>2010-07-18T00:00:00-07:00</published>
    <updated>2010-07-18T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;The second chapter of &lt;a href="http://www.amazon.com/gp/product/0262033844?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0262033844"&gt;&lt;em&gt;Introduction To Algorithms&lt;/em&gt;&lt;/a&gt; by Cormen, Leiserson, et al., describes the algorithms for Insertion Sort and Merge Sort in pseudocode, and compares their relative efficiency (or lack thereof). I decided to write them out in Ruby and run some simple benchmarks, just for fun&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;The second chapter of &lt;a href="http://www.amazon.com/gp/product/0262033844?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0262033844"&gt;&lt;em&gt;Introduction To Algorithms&lt;/em&gt;&lt;/a&gt; by Cormen, Leiserson, et al., describes the algorithms for Insertion Sort and Merge Sort in pseudocode, and compares their relative efficiency (or lack thereof). I decided to write them out in Ruby and run some simple benchmarks, just for fun.&lt;/p&gt;

&lt;h2&gt;Insertion Sort&lt;/h2&gt;


&lt;p&gt;There are a variety of ways one could write the insertion sort in Ruby; this is more or less an literal translation of the &lt;em&gt;Intro to Algorithms&lt;/em&gt; pseudocode to ruby &amp;mdash; it could perhaps be made a little more ruby-ish, but here&amp;rsquo;s my version:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
def insertion_sort(sequence)
  sequence[1..sequence.size].each_with_index do |j, index|
    i = index
    sequence[0..i].reverse.each do |k|
      break unless k &gt; j
      sequence[i + 1] = k
      i = i - 1
    end
    sequence[i+1] = j
  end
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;In a nutshell:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with the second element (index 1).&lt;/li&gt;
&lt;li&gt;Save the index in a local variable, because we&amp;rsquo;re going to use it to figure out which array element to swap the current element into.&lt;/li&gt;
&lt;li&gt;Take the sub-array 0..i (where &lt;em&gt;i&lt;/em&gt; is the current index being looked at), and go backwards until the element in your inner loop is less than the current element from the outer loop, also decrementing &lt;em&gt;i&lt;/em&gt; each iteration.&lt;/li&gt;
&lt;li&gt;Copy the element in index [i] to index [i + 1]&lt;/li&gt;
&lt;li&gt;Outside the inner loop, we&amp;rsquo;ll put the current element at [i + 1].&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;In case this is a little unclear, it would go something like this:&lt;/p&gt;

&lt;p&gt;Starting array: [5,2,3,1,4,0]&lt;/p&gt;

&lt;p&gt;First pass: [&lt;strong&gt;2&lt;/strong&gt;,&lt;em&gt;5&lt;/em&gt;,3,1,4,0]&lt;/p&gt;

&lt;p&gt;Second pass: [2,&lt;strong&gt;3&lt;/strong&gt;,&lt;em&gt;5&lt;/em&gt;,1,4,0]&lt;/p&gt;

&lt;p&gt;Third pass: [&lt;strong&gt;1&lt;/strong&gt;,&lt;em&gt;2&lt;/em&gt;,&lt;em&gt;3&lt;/em&gt;,&lt;em&gt;5&lt;/em&gt;,4,0]&lt;/p&gt;

&lt;p&gt;Fourth pass: [1,2,3,&lt;strong&gt;4&lt;/strong&gt;,&lt;em&gt;5&lt;/em&gt;,0]&lt;/p&gt;

&lt;p&gt;Fifth pass: [&lt;strong&gt;0&lt;/strong&gt;,&lt;em&gt;1&lt;/em&gt;,&lt;em&gt;2&lt;/em&gt;,&lt;em&gt;3&lt;/em&gt;,&lt;em&gt;4&lt;/em&gt;,&lt;em&gt;5&lt;/em&gt;]&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Bold elements&lt;/strong&gt; are the ones which were the &amp;ldquo;current&amp;rdquo; element moved back, &lt;em&gt;italic elements&lt;/em&gt; are the ones that had to be shifted forward in this step.)&lt;/p&gt;

&lt;h2&gt;Merge Sort&lt;/h2&gt;


&lt;p&gt;The merge sort is split into two parts; a &lt;code&gt;merge&lt;/code&gt; method that acts as a helper, and the actual &lt;code&gt;merge_sort&lt;/code&gt; which calls itself recursively, also calling &lt;code&gt;merge&lt;/code&gt; when needed.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a version modeled after the pseudocode in &lt;em&gt;Intro to Algorithms&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
def merge_sort(sequence, first, last)
  if first &lt; last
    mid = (first + last) / 2
    merge_sort(sequence, first, mid)
    merge_sort(sequence, mid + 1, last)
    merge(sequence, first, mid + 1, last)
  end
end

def merge(sequence, first, mid, last)
  left = sequence[first..mid - 1]
  right = sequence[mid..last]
  left.push(Float::MAX)
  right.push(Float::MAX)
  i = 0
  j = 0
  (first..last).each do |n|
    if left[i] &lt;= right[j]
      sequence[n] = left[i]
      i = i + 1
    else
      sequence[n] = right[j]
      j = j + 1
    end
  end
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;A few notes: You&amp;rsquo;ll notice that in the &lt;code&gt;merge&lt;/code&gt; method, when the sequence is split into two parts, the value Float::MAX is pushed onto each as the final element. &lt;em&gt;Intro to Algorithms&lt;/em&gt; uses the idea that &amp;ldquo;infinity&amp;rdquo; is set to the last element. Hopefully I can explain why in the description of the algorithm.&lt;/p&gt;

&lt;p&gt;First, the merge method. The merge method assumes that the left half and the right half of the section of the array it&amp;rsquo;s looking at are &lt;em&gt;already sorted&lt;/em&gt;. Having made this assumption, it loops through the range it&amp;rsquo;s considering (&lt;code&gt;first..last&lt;/code&gt;), and puts either the first element of the left side, or the first element of the right side, whichever it least. It increments each subarray as it goes; when it gets past the last element of either array, Float::MAX will &lt;em&gt;always&lt;/em&gt; be higher (or so we assume, for the sake of this implementation) than whatever is in the other array. So merge finishes up, basically (ahem) &lt;em&gt;merging&lt;/em&gt; the two halves together in place, with the whole first..last range sorted.&lt;/p&gt;

&lt;p&gt;Now, the actual merge_sort method. It first checks to see if first &amp;lt; last; if this were &lt;em&gt;false&lt;/em&gt;, then the range would be an array of size 1, and an array of size 1 is already sorted. So assuming the range first..last is &gt; 1, it calculates a midpoint; integer division works fine for this, using &lt;code&gt;(first + last) / 2&lt;/code&gt;. Then it calls itself recursively on each subarray; these in turn will continue splitting each subarray into two parts until it gets to the point where it&amp;rsquo;s just two subarrays of one element each; which are then fed to &lt;code&gt;merge&lt;/code&gt; and sorted. As the method returns from each level of recursion, each &amp;ldquo;half&amp;rdquo; of the subarray under consideration has been sorted, until it gets all the way back to the first call to &lt;code&gt;merge_sort&lt;/code&gt;, and executes &lt;code&gt;merge&lt;/code&gt; on each (sorted) half of the full array.&lt;/p&gt;

&lt;p&gt;Phew. I&amp;rsquo;m going to attempt to show another example, in case that&amp;rsquo;s helpful. Let&amp;rsquo;s say we started with the same starting array as the insertion_sort example. This time, to show what the recursion is actually doing, I&amp;rsquo;ll write out what each nested call to merge_sort( and/or merge) would actually look like:&lt;/p&gt;

&lt;p&gt;Starting array: [5,2,3,1,4,0]&lt;/p&gt;

&lt;pre style="font-size:0.8em !important;"&gt;
merge_sort([5,2,3,1,4,0], 0, 5):
  mid &lt;- 2
  merge_sort([5,2,3], 0, 2):
    mid &lt;- 1
    merge_sort([5,2], 0, 1):
      mid &lt;- 0
      merge_sort([5], 0, 0):
      merge_sort([2], 1, 1):
      merge([5,2],0, 1, 1):
        left &lt;- [5,&amp;infin;]
        right &lt;- [2,&amp;infin;]
        loop(0..1):
          [2,5] # just showing the result in this step; the two elements are sorted.
    merge_sort([3], 2, 2):
    merge([2,5,3], 0, 2, 2):
      left &lt;- [2,5,&amp;infin;]
      right &lt;- [3,&amp;infin;]
      loop(0..2):
        [2,3,5]
  merge_sort([1,4,0], 3, 5):
    mid &lt;- 4
    merge_sort([1,4], 3, 4):
      mid &lt;- 3
      merge_sort([1], 3, 3):
      merge_sort([4], 4, 4):
      merge([1,4], 3, 4, 4):
        left &lt;- [1,&amp;infin;]
        right &lt;- [4,&amp;infin;]
        loop(3..4):
          [1,4]
    merge_sort([0], 5, 5):
    merge([1,4,0], 3, 5, 5):
      left &lt;- [1,4,&amp;infin;]
      right &lt;- [0,&amp;infin;]
      loop(3..5):
        [0,1,4]
  merge([2,3,5,0,1,4], 0, 3, 5):
    left &lt;- [2,3,5,&amp;infin;]
    right &lt;- [0,1,4,&amp;infin;]
    loop(0..5):
      [0,1,2,3,4,5]
&lt;/pre&gt;


&lt;p&gt;Uhm, hopefully that&amp;rsquo;s clear. If you&amp;rsquo;re bothering to read this and it still isn&amp;rsquo;t clear, just run the sort locally and add some &lt;code&gt;print&lt;/code&gt; or &lt;code&gt;puts&lt;/code&gt; statements liberally so you can see what&amp;rsquo;s going on. Note: I did take a liberty in the above listing of what&amp;rsquo;s happening; in actuality the entire array is passed each time; I made it look as though just the subarray were being passed in each case, because that is the only part that is being looked at in each nested section. Again, if you&amp;rsquo;re interested enough in the topic that you&amp;rsquo;re still working out this algorithm, fire up irb and just try it out, it will make more sense as you do so.&lt;/p&gt;

&lt;h2&gt;Wait, why is this called "how &lt;em&gt;not&lt;/em&gt; to write sorting algorithms...?"&lt;/h2&gt;


&lt;p&gt;Aha. I thought you&amp;rsquo;d never ask. Well, the main reason is that both of these methods are significantly slower than good old Array::sort, which is built in to Ruby (and which, as far as I know, is implemented using the &lt;a href="http://en.wikipedia.org/wiki/Quicksort"&gt;quicksort&lt;/a&gt; algorithm).&lt;/p&gt;

&lt;p&gt;So, just for fun, I wrote a little script to make some benchmarks of these various methods on arrays of various sizes. Here were the results:&lt;/p&gt;

&lt;pre style="font-size:0.8em !important;"&gt;
      user     system      total        real

 small_array has 100 elements in it...
Insertion Sort (small_array): 
  0.000000   0.000000   0.000000 (  0.002122)
Merge sort (small_array): 
  0.000000   0.000000   0.000000 (  0.001499)
Ruby Array::sort (small_array): 
  0.000000   0.000000   0.000000 (  0.000016)

 bigger_array has 1000 elements in it...
Insertion sort (bigger_array): 
  0.240000   0.000000   0.240000 (  0.238994)
Merge sort (bigger array): 
  0.030000   0.010000   0.040000 (  0.027746)
Ruby Array::sort (bigger_array): 
  0.000000   0.000000   0.000000 (  0.000161)

 medium_array has 10,000 elements in it...
Insertion sort (medium_array): 
 23.960000   0.010000  23.970000 ( 24.096455)
Merge sort (medium_array): 
  0.720000   0.020000   0.740000 (  0.726312)
Ruby Array::sort (medium_array): 
  0.000000   0.000000   0.000000 (  0.001637)

 huge_array has 100,000 elements in it...
Sorry, the insertion_sort was taking too long! Skipped it.
Merge sort (huge_array): 
 61.710000  11.990000  73.700000 ( 74.332743)
ruby Array::sort (huge_array): 
  0.020000   0.000000   0.020000 (  0.020800)


&lt;/pre&gt;


&lt;p&gt;The interesting column is the last one: &lt;em&gt;real&lt;/em&gt;, as in &amp;ldquo;real time&amp;rdquo; (more or less, taking into the account that we&amp;rsquo;re just benchmarking).&lt;/p&gt;

&lt;p&gt;The small array is pretty fast for all three methods, but even still, we can see that merge_sort is a &lt;em&gt;little&lt;/em&gt; faster, and the built in .sort! (using quicksort) is &lt;em&gt;way&lt;/em&gt; faster: only 0.000016 seconds.&lt;/p&gt;

&lt;p&gt;The next bigger, bigger_array, the differences stand out a little more. Insertion takes 0.24 seconds, merge takes 0.028, and sort! (again), way faster, only 0.00016 seconds.&lt;/p&gt;

&lt;p&gt;A ten thousand element array starts to show the difference even more dramatically: insertion_sort now takes 24.1 seconds, close to half a minute, while the merge_sort still runs in under a second. sort!, once again, is blowing them away at only 0.0016 seconds.&lt;/p&gt;

&lt;p&gt;Finally, a hundred thousand element array; sorry for the lack of stats, but I was too impatient to let insertion_sort finish. Let&amp;rsquo;s just say it would take awhile. Now even the merge_sort shows its limits, taking over a minute, about 74.3 seconds. And finally, good old sort! clocking in at only 0.02 seconds.&lt;/p&gt;

&lt;p&gt;So the reason this is how &lt;em&gt;not&lt;/em&gt; to write sorting algorithms in ruby is simply that, you really probably don&amp;rsquo;t need to, unless you need something faster than a quicksort written in C. The reason, hopefully, to be playing around writing algorithms in Ruby or in &lt;em&gt;whatever&lt;/em&gt; your favorite language happens to be, is just to understand them better.&lt;/p&gt;

&lt;p&gt;And it&amp;rsquo;s fun.&lt;/p&gt;

&lt;p&gt;See also:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Insertion_sort"&gt;Insertion Sort&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Merge_sort"&gt;Merge Sort&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/kanwei/algorithms"&gt;Ruby Algorithm library&lt;/a&gt; &amp;lt;&amp;mdash; some pretty interesting stuff in here. I didn&amp;rsquo;t look at this until after I&amp;rsquo;d already written my versions of the insertion sort and the merge sort; their version of insertion_sort is nearly the same, but their merge sort is somewhat more succinct, and looks worth playing around with.)&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Relative Primes, Revisited</title>
    <link href="http://philcrissman.com/2010/07/08/relative-primes-revisited" rel="alternate"/>
    <id>http://philcrissman.com/2010/07/08/relative-primes-revisited</id>
    <published>2010-07-08T00:00:00-07:00</published>
    <updated>2010-07-08T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;As I thought; there&amp;rsquo;s always a better way to do it. &lt;a href="http://twitter.com/jmchilton"&gt;@jmchilton&lt;/a&gt;, who was a TA when I took Structure of Computer Programming I (or whatever it was called; the Scheme class) at the U of M, supplied this alternative solution to the relative prime problem:&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;As I thought; there&amp;rsquo;s always a better way to do it. &lt;a href="http://twitter.com/jmchilton"&gt;@jmchilton&lt;/a&gt;, who was a TA when I took Structure of Computer Programming I (or whatever it was called; the Scheme class) at the U of M, supplied this alternative solution to the relative prime problem:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
def gcd(a, b); b == 0 ? a : gcd(b, a % b); end; def rp(a, b); gcd(a, b) == 1; end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Or, indented:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
def gcd(a, b)
  b == 0 ? a : gcd(b, a % b)
end

def rp(a, b)
  gcd(a, b) == 1
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;In other words, it pays to know your math. &lt;code&gt;gcd&lt;/code&gt; is a recursive function, basically Euclid&amp;rsquo;s algorithm for finding the greatest common denominator. &lt;code&gt;rp&lt;/code&gt;, then, simply returns true if the GCD of a and b is 1; otherwise false.&lt;/p&gt;

&lt;p&gt;Very nice. I wish I&amp;rsquo;d thought to do it that way, but I&amp;rsquo;ll certainly remember it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Relative Primes</title>
    <link href="http://philcrissman.com/2010/07/07/relative-primes" rel="alternate"/>
    <id>http://philcrissman.com/2010/07/07/relative-primes</id>
    <published>2010-07-07T00:00:00-07:00</published>
    <updated>2010-07-07T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;I didn&amp;rsquo;t expect to do a &amp;ldquo;code kata&amp;rdquo;-type post again so quickly, but here it is anyways.&lt;/p&gt;

&lt;p&gt;I was reading Randall Hyde&amp;rsquo;s excellent &lt;a href="http://www.amazon.com/gp/product/1593270038?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1593270038"&gt;Writing Great Code: Volume 1&lt;/a&gt; and came across the concept of relative primes&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I didn&amp;rsquo;t expect to do a &amp;ldquo;code kata&amp;rdquo;-type post again so quickly, but here it is anyways.&lt;/p&gt;

&lt;p&gt;I was reading Randall Hyde&amp;rsquo;s excellent &lt;a href="http://www.amazon.com/gp/product/1593270038?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1593270038"&gt;Writing Great Code: Volume 1&lt;/a&gt; and came across the concept of relative primes.&lt;/p&gt;

&lt;p&gt;If you haven&amp;rsquo;t heard the term in awhile, relative primes are simply two numbers that are not both evenly divisible by the same value (not counting 1, of course).&lt;/p&gt;

&lt;p&gt;Writing some code to determine if two integers are relatively prime seemed interesting, so I gave it a first shot:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
# relprime01.rb

def rel_prime(a, b)  
  # if either number is one, they are automatically relatively prime.
  return true if (a == 1 || b == 1)
  
  # determine a's factors.
  fa = factors(a)
  # determine b's factors.
  fb = factors(b)
  
  # are any factors the same? then false
  # if no factors are shared, then true.
  # ie, if the intersect is empty, true, else false.
  (fa &amp; fb).empty?
  
end

def factors(a)
  return a if a == 1
  (2..a).map{|k| k if a%k==0 }.compact
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So, open up irb, &lt;code&gt;require &amp;lsquo;rel_prime01.rb&amp;rsquo;&lt;/code&gt;, and you have a method for determining if 2 integers are relatively prime. It has some issues, and would not be very efficient for large values. Before addressing that, I thought I&amp;rsquo;d just go straight to monkeypatching &lt;code&gt;Integer&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;Note: there&amp;rsquo;s another problem with the above method, too. See it? See below the next listing for what it is.&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
# rel_prime02.rb

class Integer

  # usage: x.rel_prime?(y)
  # returns true if x and y are relatively prime.
  def rel_prime?(n)
    return true if (self.abs == 1 || n.abs == 1)
    
    # All number pairs have 1 as a shared factor; it doesn't count. So we subtract it from the array before checking [ ].empty?
    ((self.factors &amp; n.factors) - [1]).empty?
  end

  # usage: x.factors
  # returns an array of the factors of x
  def factors
    (1..self.abs).map{|k| k if self.abs%k==0 }.compact
  end
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Essentially the same algorithm; if either integer is 1, then the numbers are automatically relative primes; 1 has no factors other than itself, so the only factor they share is 1. If both numbers are not 1, it gets the full list of factors of both numbers, checks to see if they have any in common, returns false if they do, and true if they don&amp;rsquo;t.&lt;/p&gt;

&lt;p&gt;The problem fixed in the second code is the use of Integer::abs in the appropriate places; that first code listing would blow up if you supplied a negative integer. Negative integers should be allowed, so this code uses .abs to make everything work properly, as it should.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s still a big problem for checking large numbers. Each time we check relative primes, we&amp;rsquo;re getting ALL the factors of each integer, and then comparing them when we&amp;rsquo;re done. That could take a really long time, and the code above iterates though every single value from &lt;code&gt;1..x&lt;/code&gt; for each &lt;code&gt;x&lt;/code&gt; we give it&amp;hellip; even if that number turns out to be (gasp!) prime. This won&amp;rsquo;t do at all. It will give us correct answers, but it will take a really long time to do it if we supply large values.&lt;/p&gt;

&lt;p&gt;How could we improve it? Well, one way would be to check common factors as we go. That way, if both numbers are even, we find out they share a factor on the very first iteration, and we simply stop: they are not relatively prime. Here&amp;rsquo;s this one:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
# rel_prime03.rb

class Integer

  # usage: x.rel_prime?(y)
  # returns true if x and y are relatively prime.
  def rel_prime?(n)
    return true if (self.abs == 1 || n.abs == 1)
    
    # different approach; go through (1..min(self,n).abs), 
    # build an array for each number's factors as we go.
    # each time you add a factor, check if the two arrays share it.
    # if they do, end right away with false; 
    # else, keep searching for common factors.
    x,y =[],[]
    
    
    (2..[self,n].sort[0].abs).each do |k|
      x &lt;&lt; k if self % k  == 0
      y &lt;&lt; k if n % k     == 0
      return false unless (x &amp; y).empty?
    end
    
    # if you get here, it's because you found no common factors. return true.
    true
  end

end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So, this time we make 2 empty arrays, x and y. Each time we find a factor of self or n we add it to either x or y and then check if the intersection of those two arrays (using &amp;amp;) is empty; if it&amp;rsquo;s ever not empty, return false right away and stop checking. If we get all the way to the end without finding a common factor, we can return true.&lt;/p&gt;

&lt;p&gt;This is better; works great for large numbers IFF the common factor is a fairly low number. But what if it isn&amp;rsquo;t? What if the common factor is a 7 digit long prime number?&lt;/p&gt;

&lt;p&gt;We know that there will be cases &amp;hellip; large primes, for example &amp;hellip; where we do basically need to check all the way up till we reach the last value that could be possible (the lesser of self and n, whichever that happens to be). But there&amp;rsquo;s a lot of number in-between that we don&amp;rsquo;t need to check. For example, if 2 is not a common factor, then we never need to check multiples of 2 again. If 3 is not a common factor, we never need to check multiples of 3 again. And so on. So really, if x is the lesser of self and n, the range we need to check will look something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[2,3,5,7,11,13 &amp;hellip; x]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Hm. That list looks familiar. Basically, we only need to check to see if prime numbers are factors of self and n; if a given prime number is not a factor, neither will any of its multiples be a factor.&lt;/p&gt;

&lt;p&gt;Generating a list of primes wasn&amp;rsquo;t on the to-do list, but fortunately ruby has a class in mathn called Prime, which returns an enumerator for iterating over the prime numbers. How convenient!&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
# rel_prime04.rb
require 'mathn'

class Integer

  # usage: x.rel_prime?(y)
  # returns true if x and y are relatively prime.
  def rel_prime?(n)
    return true if (self.abs == 1 || n.abs == 1)
    
    # one more quick check; does self % n == 0?
    # if it does, we save some time; we know right away they aren't relatively prime,
    # and we don't need to iterate all the way up before we find out.
    return true if self % n == 0
    
    x,y =[],[]
    
    # Prime.instance gives us an enumerator over the Prime numbers.
    # Enumerating over only primes saves us the wasted effort 
    # of rechecking multiples of factors we've already ruled out.
    # etc.
    p = Prime.instance
    
    p.each do |k|
      x &lt;&lt; k if self % k  == 0
      y &lt;&lt; k if n % k     == 0
      return false unless (x &amp; y).empty?
      break if k &gt;= [self,n].sort[0].abs
    end
    
    # if you get here, it's because you found no common factors. return true.
    true
  end
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Now, the above code uses Prime::instance to create the enumerator, which is a ruby 1.9 thing; you can do this in ruby 1.8.x, but you&amp;rsquo;ll need &lt;code&gt;Prime.new&lt;/code&gt; instead of &lt;code&gt;Prime.instance&lt;/code&gt;. Warning, though, I found that the Prime enumerator in 1.8.x was still pretty slow for larger integers. The 1.9 version is &lt;em&gt;very&lt;/em&gt; fast. For easy ways to get ruby 1.9.x installed without messing too much with your existing environment, check out &lt;a href="http://rvm.beginrescueend.com/"&gt;rvm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So now we&amp;rsquo;re doing essentially the same as the rel_prime03.rb version, but we&amp;rsquo;re skipping the multiples of any factors we&amp;rsquo;ve already ruled out by &lt;em&gt;only&lt;/em&gt; iterating through the prime numbers. In the loop, you&amp;rsquo;ll see we stop if &lt;code&gt;k &gt;= [self,n].sort[0]&lt;/code&gt;, which is the lesser of self and n (I felt like there might be a more elegant way to quickly find the lesser of two integers, but I didn&amp;rsquo;t look; anyone?).&lt;/p&gt;

&lt;p&gt;One more thing was added, here: right at the beginning, after checking if self or n (abs) is equal to 1, we also check if self % n == 0. If it does, we just saved some time; see the comments in the listing above.&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s that, then. A method added to Integer that checks if two integers are relatively prime.&lt;/p&gt;

&lt;p&gt;Is there a better way to do it? I&amp;rsquo;m fairly certain there is (there usually is), so if you know of one, feel free to leave a note or a link in the comments.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>various fizzbuzzes</title>
    <link href="http://philcrissman.com/2010/07/06/various-fizzbuzzes" rel="alternate"/>
    <id>http://philcrissman.com/2010/07/06/various-fizzbuzzes</id>
    <published>2010-07-06T00:00:00-07:00</published>
    <updated>2010-07-06T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Every so often I remember reading posts like &lt;a href="http://www.codinghorror.com/blog/2007/02/why-cant-programmers-program.html"&gt;Why can&amp;rsquo;t programmers&amp;hellip; program?&lt;/a&gt;, or &lt;a href="http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/"&gt;Are you one of the 10% of programmers who can implement a binary search?&lt;/a&gt;, or even various things about the idea of &lt;a href="http://duckduckgo.com/?q=code+kata&amp;amp;v="&gt;code kata&lt;/a&gt;, and that makes me want to just spend a little time practicing, rather than just working. Very often while working, we&amp;rsquo;re resolving a problem we (and/or others) have solve dozens of times before, and it&amp;rsquo;s really not very challenging or stretching&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Every so often I remember reading posts like &lt;a href="http://www.codinghorror.com/blog/2007/02/why-cant-programmers-program.html"&gt;Why can&amp;rsquo;t programmers&amp;hellip; program?&lt;/a&gt;, or &lt;a href="http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/"&gt;Are you one of the 10% of programmers who can implement a binary search?&lt;/a&gt;, or even various things about the idea of &lt;a href="http://duckduckgo.com/?q=code+kata&amp;amp;v="&gt;code kata&lt;/a&gt;, and that makes me want to just spend a little time practicing, rather than just working. Very often while working, we&amp;rsquo;re resolving a problem we (and/or others) have solve dozens of times before, and it&amp;rsquo;s really not very challenging or stretching.&lt;/p&gt;

&lt;p&gt;Since I was thinking about it, I decided to just start with the FizzBuzz example, from &lt;a href="http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html"&gt;Reginald Braithwaite&lt;/a&gt; via Jeff Atwood.&lt;/p&gt;

&lt;p&gt;First solution:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
(1..100).each do |k|
  print k % 3 == 0 ? "Fizz" : ""
  print k % 5 == 0 ? "Buzz" : ""
  print k unless (k % 3 == 0 || k % 5 == 0)
  print " "
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So, that&amp;rsquo;s simple enough. I thought maybe it could be a little more compact, but essentially unchanged, here was the next version:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
(1..100).each do |k|
  print k%3==0 ? "Fizz" : "", k%5==0 ? "Buzz" : "", (k%3==0 || k%5==0) ? "" : k,  " "
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;That&amp;rsquo;s nice and all, but I&amp;rsquo;m now trying to think if I can find other ways to do it. Preferably shorter and/or more elegant. Maybe. &lt;code&gt;003.rb&lt;/code&gt; was next.&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
(1..100).each do |k|
  word = ''
  word &lt;&lt; "Fizz" if k%3==0
  word &lt;&lt; "Buzz" if k%5==0
  print word.empty? ? k : word, " "
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Not really shorter or elegant, but a slightly different approach, filling a placeholder variable with &amp;ldquo;Fizz&amp;rdquo;, &amp;ldquo;Buzz&amp;rdquo; (or both), and then deciding which one to display based on whether or not the placeholder was &lt;code&gt;empty?&lt;/code&gt; (If you aren&amp;rsquo;t familiar with Ruby, &lt;code&gt;&amp;ldquo;&amp;rdquo;.empty? == true &amp;amp;&amp;amp; &amp;ldquo;anything&amp;rdquo;.empty? == false&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;Again, I tried to pare that down a little.&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
puts (1..100).map {|k| w='';w&lt;&lt;"Fizz"if k%3==0;w&lt;&lt;"Buzz"if k%5==0;w.empty? ? k : w }.join(" ")
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Well, I don&amp;rsquo;t know if it&amp;rsquo;s readable, or anything resembling elegant, but it&amp;rsquo;s, um&amp;hellip; more compact.&lt;/p&gt;

&lt;p&gt;At that point I glanced back at my first solution, and something was bugging me about it; oh, yeah. The ternary expressions that returned &amp;ldquo;&amp;rdquo; for the false case. That seemed unnecessary. 005.rb tries to fix it.&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
(1..100).each do |k|
  print "Fizz" if k % 3 == 0
  print "Buzz" if k % 5 == 0
  print k unless (k % 3 == 0 || k % 5 == 0)
  print " "
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Essentially unchanged. I&amp;rsquo;m not even sure it&amp;rsquo;s any more efficient but it &lt;em&gt;feels&lt;/em&gt; less like there&amp;rsquo;s wasted code in there, so I like it a little better. Now, it&amp;rsquo;s not really &lt;em&gt;changing&lt;/em&gt; much, but what if we extract the logic into it&amp;rsquo;s own method?&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
def fizzbuzz(k)
  w = ''
  w &lt;&lt; "Fizz" if k%3==0
  w &lt;&lt; "Buzz" if k%5==0
  w.empty? ? k : w
end

(1..100).each {|k| print fizzbuzz(k), " " }
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Hey, that&amp;rsquo;s&amp;hellip; well, it&amp;rsquo;s essentially the same, but the lesser rites of refactoring have been appeased by pulling that code into it&amp;rsquo;s own little method.&lt;/p&gt;

&lt;p&gt;Hey. That makes me think we could just:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
class Integer
  def fizzbuzz
    w=''&lt;&lt;(self%3==0 ? "Fizz" : "")&lt;&lt;(self%5==0 ? "Buzz" : "")
    w.empty? ? self : w
  end
end

puts (1..100).map{|k| k.fizzbuzz }.join(" ")
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So, a couple different things here. We open up &lt;code&gt;Integer&lt;/code&gt; and add a fizzbuzz method to it. The idea of a place holder with either &amp;ldquo;Fizz&amp;rdquo;, &amp;ldquo;Buzz&amp;rdquo;, or both added to it is streamlined slightly by adding the concatenation lines right into the variable assignment. To make that work, we have to go back to using the ternary operator (can you see why? If we just did &lt;code&gt;w &amp;lt;&amp;lt; &amp;ldquo;Fizz&amp;rdquo; if k%3==0&lt;/code&gt;, it would try to append &lt;code&gt;nil&lt;/code&gt; to the String, and you&amp;rsquo;d get a horrible &amp;ldquo;Unable to convert nil to String&amp;rdquo; error anytime a non-multiple of 3 or 5 came up).&lt;/p&gt;

&lt;p&gt;So, that&amp;rsquo;s that. I know this is simple, maybe trivial, but hey, who wants to be the guy who couldn&amp;rsquo;t program a FizzBuzz solution in the interview?&lt;/p&gt;

&lt;p&gt;This was a fun exercise, so I&amp;rsquo;ll probably try to do some more like it. I&amp;rsquo;ll likely start by mining Code Kata, implementing some algorithms, or something. Feel free to leave problem suggestions in the comments.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Introducing henry, a theme for Toto</title>
    <link href="http://philcrissman.com/2010/06/28/introducing-henry-a-theme-for-toto" rel="alternate"/>
    <id>http://philcrissman.com/2010/06/28/introducing-henry-a-theme-for-toto</id>
    <published>2010-06-28T00:00:00-07:00</published>
    <updated>2010-06-28T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;As a response to no demand whatsoever, I nevertheless extracted my theme for this blog into it&amp;rsquo;s own standalone theme for &lt;a href="http://cloudhead.io/toto"&gt;toto&lt;/a&gt; that you could use just like &lt;a href="http://github.com/cloudhead/dorothy"&gt;dorothy&lt;/a&gt;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;As a response to no demand whatsoever, I nevertheless extracted my theme for this blog into it&amp;rsquo;s own standalone theme for &lt;a href="http://cloudhead.io/toto"&gt;toto&lt;/a&gt; that you could use just like &lt;a href="http://github.com/cloudhead/dorothy"&gt;dorothy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keeping with the Oz names, I called it &lt;a href="http://github.com/philcrissman/henry"&gt;henry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Installation is pretty much identical as you would to for toto and dorothy:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="bash"&gt;
gem install toto
git clone git://github.com/philcrissman/henry.git myblog
cd myblog
heroku create myblog
git push heroku master
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Now, I pretty much completely disregarded IE support when I designed the blog, so as a result I don&amp;rsquo;t think henry will look like anything much in IE. You&amp;rsquo;re on your own. I will probably eventually feel like I should update this or address it somehow, but I&amp;rsquo;m not making any guarantees as to when that would be.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Rails Links 001</title>
    <link href="http://philcrissman.com/2010/06/25/rails-links-001" rel="alternate"/>
    <id>http://philcrissman.com/2010/06/25/rails-links-001</id>
    <published>2010-06-25T00:00:00-07:00</published>
    <updated>2010-06-25T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;As an experiment, I&amp;rsquo;m going to start making a link-post every so often. Maybe weekly? We&amp;rsquo;ll see.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eric Davis provides a big &lt;a href="http://theadmin.org/articles/2010/06/24/capistrano-variables/"&gt;list of Capistrano variables&lt;/a&gt; (via &lt;a href="http://larkware.com/shots"&gt;larkgroup&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

</summary>
    <content type="html">&lt;p&gt;As an experiment, I&amp;rsquo;m going to start making a link-post every so often. Maybe weekly? We&amp;rsquo;ll see.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eric Davis provides a big &lt;a href="http://theadmin.org/articles/2010/06/24/capistrano-variables/"&gt;list of Capistrano variables&lt;/a&gt; (via &lt;a href="http://larkware.com/shots"&gt;larkgroup&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fabio Akita took the opportunity to &lt;a href="http://www.rubyinside.com/quality-interviews-with-10-rubyists-and-bob-martin-3458.html"&gt;interview&lt;/a&gt; a bunch of folks at RailsConf (via &lt;a href="http://rubyinside.com"&gt;RubyInside&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;You still have time to take Hampton Catlin&amp;rsquo;s 2010 &lt;a href="http://survey.hamptoncatlin.com/"&gt;Ruby Survey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Some thoughts on &lt;a href="http://ducktypo.blogspot.com/2010/06/new-ruby-ecosystem.html"&gt;the new Ruby ecosystem&lt;/a&gt; from Paolo Perrotta (via &lt;a href="http://coder.io"&gt;coder.io&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Also, feedback appreciated. Is this sort of post useful, informative, handy? Or overdone, redundant, irrelevant? Somewhere in between?&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>It's unanimous</title>
    <link href="http://philcrissman.com/2010/06/23/its-unanimous" rel="alternate"/>
    <id>http://philcrissman.com/2010/06/23/its-unanimous</id>
    <published>2010-06-23T00:00:00-07:00</published>
    <updated>2010-06-23T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="/images/posts/bones-nod-kirk-nod.gif" /&gt;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="/images/posts/bones-nod-kirk-nod.gif" /&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>WhinyRendering</title>
    <link href="http://philcrissman.com/2010/06/18/whinyrendering" rel="alternate"/>
    <id>http://philcrissman.com/2010/06/18/whinyrendering</id>
    <published>2010-06-18T00:00:00-07:00</published>
    <updated>2010-06-18T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Quite often I&amp;rsquo;ll come into a Rails project with a good portion of the code already written. Depending on style the developers were using, this sometimes means that I may not be able to easily tell, when looking at a given view, how the view is being generated. The URL may &lt;em&gt;say&lt;/em&gt; /pages/1, but for all I know, the routes file has instructions to use the ArmpitsController when it sees a route for pages/*; the URL might say /user/login, but for all we know, that may map to SessionController::sign_in. In other words, it&amp;rsquo;s not always clear&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Quite often I&amp;rsquo;ll come into a Rails project with a good portion of the code already written. Depending on style the developers were using, this sometimes means that I may not be able to easily tell, when looking at a given view, how the view is being generated. The URL may &lt;em&gt;say&lt;/em&gt; /pages/1, but for all I know, the routes file has instructions to use the ArmpitsController when it sees a route for pages/*; the URL might say /user/login, but for all we know, that may map to SessionController::sign_in. In other words, it&amp;rsquo;s not always clear.&lt;/p&gt;

&lt;p&gt;And that&amp;rsquo;s not even getting into the cases where there are multiple partials being used, some of which might be in app/views/shared, or who knows where.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ve talked in the office a few times about a mythical plugin that could provide a little output stating exactly what controller, action, and template are being rendered, as well as any and all partials. Thus the idea for WhinyRendering was born.&lt;/p&gt;

&lt;p&gt;If any of the preceding scenario sounds familiar, I hope it&amp;rsquo;s helpful.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/philcrissman/whiny_rendering"&gt;WhinyRendering&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>All Your Webs</title>
    <link href="http://philcrissman.com/2010/06/17/all-your-webs" rel="alternate"/>
    <id>http://philcrissman.com/2010/06/17/all-your-webs</id>
    <published>2010-06-17T00:00:00-07:00</published>
    <updated>2010-06-17T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Taptaptap made an extension that &lt;a href="http://taptaptap.com/blog/speaking-of-comments/"&gt;adds comments&lt;/a&gt; to &lt;a href="http://daringfireball.net"&gt;Daring Fireball&lt;/a&gt;, and, as you can see in the comments, sparked a little debate on whether or not this was A Good Thing&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Taptaptap made an extension that &lt;a href="http://taptaptap.com/blog/speaking-of-comments/"&gt;adds comments&lt;/a&gt; to &lt;a href="http://daringfireball.net"&gt;Daring Fireball&lt;/a&gt;, and, as you can see in the comments, sparked a little debate on whether or not this was A Good Thing.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s fine. I mean, I don&amp;rsquo;t really care if I can comment on DF or not, but if someone wants to, and if people use this and like it, great. It&amp;rsquo;s the web. You can&amp;rsquo;t control how people view your page. They could view it on any browser, with any extension, greasemonkey script, or other shenanigans inbetween, and there is absolutely nothing you or I can do about it.&lt;/p&gt;

&lt;p&gt;They can &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/1865/"&gt;block&lt;/a&gt; &lt;a href="https://chrome.google.com/extensions/detail/gighmmpiobklfepjocnamgkkbiglidom"&gt;your&lt;/a&gt; &lt;a href="http://safariadblock.com/"&gt;ads&lt;/a&gt;. And that&amp;rsquo;s fine, because it&amp;rsquo;s their computer, and they can do that if they want to. Period.&lt;/p&gt;

&lt;p&gt;They can implement their own stylesheets for your site (yes! they can!) and they will never again see the letter-spacing and line-height choices you painstakingly tested and implemented the last time you redesigned your blog. They can view your articles through &lt;a href="http://lab.arc90.com/experiments/readability/"&gt;Readability&lt;/a&gt; or something like it.&lt;/p&gt;

&lt;p&gt;It just is. That&amp;rsquo;s just how the web is set up to work. And it&amp;rsquo;s a good thing. &lt;em&gt;It doesn&amp;rsquo;t matter&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://icanhascheezburger.com/2008/01/28/funny-pictures-all-your-bass/"&gt;&lt;img src="http://icanhascheezburger.wordpress.com/files/2008/01/funny-pictures-cat-sound-studio.jpg" alt="funny pictures" /&gt;&lt;/a&gt;&lt;br /&gt;see more &lt;a href="http://icanhascheezburger.com"&gt;Lolcats and funny pictures&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>You Should Really Consider Parking Somewhere Else</title>
    <link href="http://philcrissman.com/2010/06/07/you-should-really-consider-parking-somewhere-else" rel="alternate"/>
    <id>http://philcrissman.com/2010/06/07/you-should-really-consider-parking-somewhere-else</id>
    <published>2010-06-07T00:00:00-07:00</published>
    <updated>2010-06-07T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="/images/posts/never_ever_park_here.jpg" width="440" /&gt;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="/images/posts/never_ever_park_here.jpg" width="440" /&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Design Is a Wicked Problem</title>
    <link href="http://philcrissman.com/2010/06/01/design-is-a-wicked-problem" rel="alternate"/>
    <id>http://philcrissman.com/2010/06/01/design-is-a-wicked-problem</id>
    <published>2010-06-01T00:00:00-07:00</published>
    <updated>2010-06-01T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;blockquote&gt;
[Wittel and Webber] defined a "wicked" problem as one that could be clearly defined only by solving it...
&lt;/blockquote&gt;


&lt;blockquote&gt;... One of the main differences between programs you develop in school and those you develop as a professional is that the design problems solved by school programs are rarely, if ever, wicked. ... You'd probably want to tar and feather a teacher who gave you a programming assignment, then changed the assignment as soon as you finished the design, and then changed it again just as you were about to turn in the completed program. But that very process is an everyday reality in professional programming.&lt;/blockquote&gt;

</summary>
    <content type="html">&lt;blockquote&gt;
[Wittel and Webber] defined a "wicked" problem as one that could be clearly defined only by solving it...
&lt;/blockquote&gt;


&lt;blockquote&gt;... One of the main differences between programs you develop in school and those you develop as a professional is that the design problems solved by school programs are rarely, if ever, wicked. ... You'd probably want to tar and feather a teacher who gave you a programming assignment, then changed the assignment as soon as you finished the design, and then changed it again just as you were about to turn in the completed program. But that very process is an everyday reality in professional programming.&lt;/blockquote&gt;


&lt;p&gt;&amp;mdash; Steve McConnell, &lt;a href="http://www.amazon.com/gp/product/0735619670?ie=UTF8&amp;tag=idepermin-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0735619670"&gt;&lt;em&gt;Code Complete: A Practical Handbook of Software Construction&lt;/em&gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=idepermin-20&amp;l=as2&amp;o=1&amp;a=0735619670" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Roll Your Own Computer Science Masters Program</title>
    <link href="http://philcrissman.com/2010/05/01/roll-your-own-computer-science-masters-program" rel="alternate"/>
    <id>http://philcrissman.com/2010/05/01/roll-your-own-computer-science-masters-program</id>
    <published>2010-05-01T00:00:00-07:00</published>
    <updated>2010-05-01T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Struck by some sort of errant whim to get more edumacated, I started googling Computer Science Master&amp;rsquo;s Degree programs today. Actually, I did one google search and then jumped straight to the &lt;a href="http://www.stthomas.edu/gradsoftware/programs/ms/default.html"&gt;University of St. Thomas&lt;/a&gt; page on graduate programs in software. Did a little back of the envelope thinking, noted that St. Thomas wants $762.50 per credit, and decided against a Masters degree at this point in time&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Struck by some sort of errant whim to get more edumacated, I started googling Computer Science Master&amp;rsquo;s Degree programs today. Actually, I did one google search and then jumped straight to the &lt;a href="http://www.stthomas.edu/gradsoftware/programs/ms/default.html"&gt;University of St. Thomas&lt;/a&gt; page on graduate programs in software. Did a little back of the envelope thinking, noted that St. Thomas wants $762.50 per credit, and decided against a Masters degree at this point in time.&lt;/p&gt;

&lt;p&gt;But it did get me thinking. Why would I &lt;em&gt;want&lt;/em&gt; a Masters Degree, anyways? All the reasons I could think of boiled down to these two:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I want to go into a role, career, or position that &lt;em&gt;requires&lt;/em&gt; a Masters Degree.&lt;/li&gt;
&lt;li&gt;I want to go into a role, career, or position that requires the &lt;em&gt;knowledge&lt;/em&gt; presumably attained from a Masters Degree.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;This is a pretty important distinction. Some roles might simply have a Masters as a &lt;em&gt;requirement&lt;/em&gt;. Doesn&amp;rsquo;t actually mean they care if you &lt;em&gt;know&lt;/em&gt; anything. Yes, of course, they assume that you do, and that your Masters actually means something, but really, for this type of thing, all that&amp;rsquo;s important is the piece of paper.&lt;/p&gt;

&lt;p&gt;And the truth is, I&amp;rsquo;m not really interested in any of those roles. Off the top of my head, all I could come up with in that category would be roles in a Fortune 500 or similarly credential-obsessed enterprise, or a role at a University, neither of which is something I want to pursue.&lt;/p&gt;

&lt;p&gt;On the other hand, maybe I just want to &lt;em&gt;know&lt;/em&gt; the information I might learn in a Masters program. Or maybe I have my sights on a career that really requires the &lt;em&gt;knowledge&lt;/em&gt;, but doesn&amp;rsquo;t necessarily care if I have the piece of paper or not. That sort of role might include (again, off the top of my head), the technical founder or lead in a startup, a writer or speaker about tech topics, or simply a kick-ass software developer who knows more this year than he did last year. Now &lt;em&gt;those&lt;/em&gt; sorts of things are interesting.&lt;/p&gt;

&lt;p&gt;All of which means it doesn&amp;rsquo;t really matter if I go to a University.&lt;/p&gt;

&lt;p&gt;Continuing on with this line of thought, I started mulling over the knowledge I&amp;rsquo;ve accumulated so far. How much would I attribute to college education, and how much did I teach myself? It&amp;rsquo;s a little hard to quantify, because there&amp;rsquo;s a lot of overlap, but even allowing some margin of error, the topics which I&amp;rsquo;ve taught myself have been far more useful/valuable than those I learned in my undergraduate degree (which was in Computer Science).&lt;/p&gt;

&lt;p&gt;More importantly, and maybe more telling, I have a far better grasp on the things that I&amp;rsquo;ve taught myself than I do on many of the things I &amp;ldquo;had&amp;rdquo; to learn in college. I know Ruby and Rails far better than I know Java, and I&amp;rsquo;ve had &lt;em&gt;at least&lt;/em&gt; four or five college courses dedicated to Java (most of which, &lt;em&gt;even the 4th year course in Operating Systems&lt;/em&gt;, assumed we didn&amp;rsquo;t know anything about Java or OOP and re-taught it all over again).&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m going to make a suggestion as to why this might be. I&amp;rsquo;m going to suggest that when we&amp;rsquo;re teaching something to ourselves, we hold ourselves to a higher standard than the average college course holds us.&lt;/p&gt;

&lt;p&gt;In an average college class, all that really matters is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attendance (as crazy as it sounds, evidently they actually still care if you attend class, for reasons unfathomable to me).&lt;/li&gt;
&lt;li&gt;Making an average effort to skim the material.&lt;/li&gt;
&lt;li&gt;Making an average effort to complete assignments (often can combine with #2, as usually the only material you ever need to read is whatever is pertinent to the assignment).&lt;/li&gt;
&lt;li&gt;Remembering &lt;em&gt;just enough&lt;/em&gt; information for &lt;em&gt;just long enough&lt;/em&gt; to have an adequate number of correct answers on your exams.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;(Aside: the possible exception to this is Calculus and other advanced math classes, unless you are one of those people who absorb that with a minimum of effort; you either understand Calculus (et. al.), or you don&amp;rsquo;t, you can&amp;rsquo;t really just push your way through those one. YMMV.)&lt;/p&gt;

&lt;p&gt;When you&amp;rsquo;re teaching &lt;em&gt;yourself&lt;/em&gt;, on the other hand:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;While you &lt;em&gt;are&lt;/em&gt; working at your own pace, chances are you actually want to &lt;em&gt;use&lt;/em&gt; the information or ideas that you&amp;rsquo;re learning, so you don&amp;rsquo;t want it to take forever. You may or may not have a fixed deadline in mind, but regardless, you are motivated to make progress for it&amp;rsquo;s own sake, not simply to get to the end of a semester.&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t fake yourself out. You can&amp;rsquo;t tell yourself that you know something when you know you don&amp;rsquo;t. You won&amp;rsquo;t fool yourself into thinking that you understand lambdas, or ruby blocks, or closures, or monads, or red-black trees, or any data structure or algorithm, if you &lt;em&gt;know&lt;/em&gt; that you don&amp;rsquo;t. So if it matters to you that you learn it, you just have to keep going back until you get it.&lt;/li&gt;
&lt;li&gt;Again, you have some reason that you actually &lt;em&gt;want to use&lt;/em&gt; this information. It&amp;rsquo;s not solely to check of a list (e.g., Okay, I have memorized a bunch of ideas about Design Patterns, check), but it&amp;rsquo;s because you want to &lt;em&gt;do&lt;/em&gt; something with the knowledge once you have it (e.g., Okay, I&amp;rsquo;ve learned some design patterns. Am I using any of these in my software side projects? If I did use one, would it improve my application? Can I identify these patterns if I see them in the wild? Etc.)&lt;/li&gt;
&lt;li&gt;Not only can you not fake yourself out, you probably underestimate yourself. When you&amp;rsquo;re teaching yourself, your often painfully aware of how much you still &lt;em&gt;don&amp;rsquo;t&lt;/em&gt; know, how much you still have left to learn, and it frequently blinds you to how much you&amp;rsquo;ve actually learned so far. Why is this good? Well, eventually you do need to recognize your progress and give yourself a pat or two on the back, but in general I think it&amp;rsquo;s good because it means you&amp;rsquo;ll push yourself harder to learn more. A good way to gauge your progress is to join a forum, a StackOverflow-type site, or an IRC chat room in the area you&amp;rsquo;re studying, and look at the questions people are asking. Chances are you&amp;rsquo;re going to find that a lot of people are asking questions that you (gasp) already know the answers to (now would be a nice time to help them, if you have time). That&amp;rsquo;s a good sign.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Now, self-discipline, which I didn&amp;rsquo;t mention, may or may not be an issue. An oft-mentioned advantage of college or course-work in general is that it pushes you to learn faster because of the built in deadlines, exams and assignments. The problem is, as I argued above, that yes, it may push you to accomplish specific milestones, but all too often this means you are &lt;em&gt;pushed to accomplish the bare minimum with the least effort at the last minute&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And don&amp;rsquo;t tell me that means I&amp;rsquo;m just &amp;ldquo;not a very good student&amp;rdquo;, then. Sure, if you can combine powerful self-motivation with college coursework, you can get more than the &amp;ldquo;minimum&amp;rdquo; amount of education from a class, and some students do. So have I, in some courses.&lt;/p&gt;

&lt;p&gt;But for better or worse, I&amp;rsquo;ve found that in many courses the combination of arbitrary requirements (i.e., the need to be present in class), &lt;em&gt;horrible&lt;/em&gt; textbooks, frequently unenthusiastic professors (sorry guys; to be &lt;em&gt;interesting&lt;/em&gt; you have to &lt;em&gt;be interested&lt;/em&gt; in what you&amp;rsquo;re talking about), and a highly subjective qualification for success (complete these &lt;em&gt;n&lt;/em&gt; assignments and learn these &lt;em&gt;n&lt;/em&gt; concepts well enough to pass an exam or two), means that the very structure and implementation of a college class encourages you to do &lt;em&gt;just enough to get by and no more&lt;/em&gt;, period.&lt;/p&gt;

&lt;p&gt;(Aside: on horrible textbooks: the only textbooks I&amp;rsquo;ve wanted to keep from my entire time obtaining a computer science degree have been Sipser&amp;rsquo;s &lt;cite&gt;&lt;a href="http://www.amazon.com/gp/product/0534950973?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0534950973"&gt;Introduction to the Theory of Computation&lt;/a&gt;&lt;/cite&gt; and Larman&amp;rsquo;s &lt;cite&gt;&lt;a href="http://www.amazon.com/gp/product/0131489062?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0131489062"&gt;Applying UML and Patterns&lt;/a&gt;&lt;/cite&gt;; and of those, I gotta say, the Larman book is pretty boring (sorry, Craig, maybe we can blame your editors), but there&amp;rsquo;s some good material in there.)&lt;/p&gt;

&lt;p&gt;So, enough complaining about colleges. I don&amp;rsquo;t really have any suggestions for how to fix the education system, if indeed it is broken &amp;mdash; I&amp;rsquo;ll leave it to others to debate and solve that problem. But since I&amp;rsquo;m convinced that self-learning is more productive and more effective, then if I&amp;rsquo;m interested in the information that I might learn in a Masters Program in Computer Science, it seems reasonable that I&amp;rsquo;d be better off concocting my own program and just starting to plug away.&lt;/p&gt;

&lt;p&gt;At the top of this article I put a link to the University of St. Thomas' graduate program in Software Engineering. Suppose we take that as a model and make a plan.&lt;/p&gt;

&lt;p&gt;Required courses we have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Foundations of Software Development. It&amp;rsquo;s waivable with experience, and if you&amp;rsquo;re even reading or contemplating doing something remotely like this, I&amp;rsquo;m going to guess you and I can waive this one. We&amp;rsquo;re assuming you can already code your way out of a paper bag, people. If you can&amp;rsquo;t do the &lt;a href="http://www.codinghorror.com/blog/2007/02/why-cant-programmers-program.html"&gt;FizzBuzz problem&lt;/a&gt; or &lt;a href="http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/"&gt;write a binary search given the description&lt;/a&gt;, then you can&amp;rsquo;t waive this. Get up to speed, folks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Technical Communication. Writing and speaking. I can see it being useful, but you&amp;rsquo;re going to have to decide if it something you want to be good at it. If it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a technical blog. Force yourself to do it semi-regularly. Explain a concept, how you solved a problem, why something is the way it is, etc. You&amp;rsquo;re not doing it to become a ProBloggerSuperStar, you&amp;rsquo;re doing it to improve your written communication skills.&lt;/li&gt;
&lt;li&gt;Find &amp;amp; join a local users group in your field of interest (say, Ruby, Java, Cocoa, whatever) and give a presentation. At least one, to start. In anything. If this is something you want to be a lot better at, try to think of several presentations you could give; then volunteer to give them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Software Engineering. Read (or re-read) &lt;cite&gt;&lt;a href="http://www.amazon.com/gp/product/0735619670?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0735619670"&gt;Code Complete&lt;/a&gt;&lt;/cite&gt;. The St. Thomas course description also includes the idea of estimating, so Mike Cohn&amp;rsquo;s &lt;cite&gt;&lt;a href="http://www.amazon.com/gp/product/0131479415?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0131479415"&gt;Agile Estimating And Planning&lt;/a&gt;&lt;/cite&gt; might also be apropos. If you&amp;rsquo;ve read both of those, then scan them to make sure you&amp;rsquo;re still up to speed and either a) give yourself a pass, you&amp;rsquo;ve got this one, or b) re-read or pick an alternate/more advanced tome on the subject and plow through it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database Management Systems And Design. I&amp;rsquo;m assuming you already know and use regularly at least one or more DB system; probably MySQL, but possibly sqlite, Postgres, or even MS SQL Server or Oracle. Great. Maybe you even know CouchDB or MongoDB or some other NoSQL system. Well, this is a Masters program. That&amp;rsquo;s Not Good Enough.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give yourself a refresher in DB design, SQL, maybe relational algebra if you like that sort of thing. &lt;em&gt;&lt;a href="http://www.amazon.com/gp/product/0596100124?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0596100124"&gt;Database in Depth&lt;/a&gt;&lt;/em&gt; is a good book. You might know others.&lt;/li&gt;
&lt;li&gt;Learn another system, whatever seems most useful to what you are doing (remember a HUGE key in making this work is that it must be something you really want to know about; follow what interests you): maybe a NoSQL db, or maybe Postgres. Learn what makes this DB different from others, from what you know already, and why. Try to figure out real reasons and/or scenarios you&amp;rsquo;d want to use one or the other.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OOAAD (Object Oriented Application Analysis and Design). Well you could read or re-read &lt;a href="http://www.amazon.com/gp/product/0131489062?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0131489062"&gt;Larman&lt;/a&gt; or &lt;a href="http://www.amazon.com/gp/product/020189551X?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=020189551X"&gt;Booch&lt;/a&gt;, and that&amp;rsquo;s probably not a bad idea. Try to make it applicable to things you want to work on, as always.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Software Project Management. This is an area I could probably stand to improve in; I&amp;rsquo;m not certain, but I think I&amp;rsquo;d start with one or more of Scott Berkun&amp;rsquo;s books (&lt;a href="http://www.amazon.com/gp/product/0596007868?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0596007868"&gt;The Art of Project Management&lt;/a&gt;, &lt;a href="http://www.amazon.com/gp/product/0596517718?ie=UTF8&amp;amp;tag=idepermin-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0596517718"&gt;Making Things Happen&lt;/a&gt;) on the topic, which seem to have attained a sort of Gold Standard status. If you&amp;rsquo;re certification-minded you might reach for a PMP-based book. I&amp;rsquo;m not gung-ho on certifications, but maybe you think it will be good to have; and honestly, of all the certs out there, this one seems the most useful. If you have experience with PMP pro or con that you&amp;rsquo;d like to leave in the comments, please do, but remember that the whole point of this plan is to be more interested in &lt;em&gt;results&lt;/em&gt; than &lt;em&gt;whether or not my certification can get me a job with SAP&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Software Quality Assurance. This would be the ideal place to learn even more about software testing. Aside from that, I would have to look for some specific material pertinent to Software QA; suggestions welcome.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Operating Systems. Yeah, I guess it&amp;rsquo;s useful. And maybe it&amp;rsquo;s super-interesting to you; at the moment it&amp;rsquo;s not an area of intense interest to me, but I can see its applicability. I&amp;rsquo;d probably start by identifying the areas in which this sort of knowledge will help the most; probably in the areas of processes, threads, memory management and related themes. Might want to brush out the old C programming toolset and pick up a book on the Linux kernel; I don&amp;rsquo;t know. Again, if the only point is to check another item off the checklist, it probably will be hell to learn and you might not even bother. So find a way to make it interesting. Maybe just spend awhile really learning or re-learning multi-threaded application programming.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Computer and Network Communications. Again, I&amp;rsquo;m guessing we have the foundations of &lt;em&gt;at least&lt;/em&gt; some or much of this down. So find an area of interest to you and push your knowledge further. Learn &lt;a href="http://nodejs.org"&gt;Node.js&lt;/a&gt; and write a server. Find an Open Source server/networking project and attempt to contribute something to it (even if it&amp;rsquo;s just documentation; come to think of it, contributing to a related OSS project would be a fantastic progress gauge for every area on this list.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;5+ electives. There&amp;rsquo;s always more to learn; what are you most interested in?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Applied Statistics/Machine Learning/Analysis&lt;/li&gt;
&lt;li&gt;Other Maths? Go nuts.&lt;/li&gt;
&lt;li&gt;Another programming language. Lisp, Erlang, Python, Ruby, C(++/#), Objective-C/Cocoa, Javascript&amp;hellip; pick something that you don&amp;rsquo;t know that you&amp;rsquo;d &lt;em&gt;like&lt;/em&gt; to know, and start knowing it. Since one of the major hurdles in learning a new language is the &amp;ldquo;what the heck should I write in this language?&amp;rdquo; problem, a good tactic might be to apply your new language to one of the above subject areas; do your DB, Networking, or QA/testing explorations in a language other than the ones you already know.&lt;/li&gt;
&lt;li&gt;Security. Big topic.&lt;/li&gt;
&lt;li&gt;Cryptography. Related to security, but also a big topic all on its own.&lt;/li&gt;
&lt;li&gt;Algorithms and Data Structures. We all probably have some exposure to these, but if it&amp;rsquo;s an area of interest to you, I&amp;rsquo;m betting you&amp;rsquo;ll always learn something from a refresher course.&lt;/li&gt;
&lt;li&gt;Data Warehousing/Mining/etc.&lt;/li&gt;
&lt;li&gt;Distributed Databases or servers.&lt;/li&gt;
&lt;li&gt;Real Time systems/concepts.&lt;/li&gt;
&lt;li&gt;Artificial Intelligence, related research.&lt;/li&gt;
&lt;li&gt;&amp;hellip;. ? I don&amp;rsquo;t know, you pick something you&amp;rsquo;re interested in.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;There&amp;rsquo;s some of the above I feel like I have a decent grasp of, there&amp;rsquo;s some that I don&amp;rsquo;t. There&amp;rsquo;s some things that interest me, and that applies directly to the ways I pay the bills each month, so obviously those are the things I&amp;rsquo;d probably gravitate towards learning first.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not going to &amp;ldquo;log my progress&amp;rdquo; on following this or any similar plan, but my point is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s doable.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s valuable in and of itself.&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t need to spend 20K+ at a university to do it.&lt;/li&gt;
&lt;li&gt;If/when you really have a grasp of all (or even MOST) of the above, you&amp;rsquo;re a software engineer who really knows his/her stuff, and especially if you can show the Open Source or other projects that you&amp;rsquo;ve contributed to along the way&amp;hellip; you really don&amp;rsquo;t need the piece of paper from the university.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If you don&amp;rsquo;t like my list, or the books/ideas I&amp;rsquo;ve listed, make your own. Or, you know, whatever. I think most really good developers plan to keep learning continuously anyways, and are probably already doing so; this just happens to be a little more structured list based off a given Masters program description. Part of my whole theory here is that you&amp;rsquo;re going to be more successful if you&amp;rsquo;re trying to learn things that really interest you, or that you really want to use, so if you don&amp;rsquo;t &lt;em&gt;care&lt;/em&gt; about project management, or networking, or databases, then by all means, just &lt;em&gt;skip it&lt;/em&gt;. Focus on what you want to know. Maybe you&amp;rsquo;d rather jump straight in to statistics and machine learning. Go download &lt;em&gt;&lt;a href="http://www.r-project.org/"&gt;R&lt;/a&gt;&lt;/em&gt; and have a ball.&lt;/p&gt;

&lt;p&gt;Comments, suggestions, hate mail, fan fiction, can be submitted below. Thanks for reading.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Validating Nested Attributes on Update</title>
    <link href="http://philcrissman.com/2010/04/12/validating-nested-attributes-on-update" rel="alternate"/>
    <id>http://philcrissman.com/2010/04/12/validating-nested-attributes-on-update</id>
    <published>2010-04-12T00:00:00-07:00</published>
    <updated>2010-04-12T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;So, let&amp;rsquo;s say you have a model, and a has_many relationship to another model. You want to accept nested attributes for the child models in your forms, and you also want to validate that the children must be present; the parent model can&amp;rsquo;t be saved unless it has &lt;em&gt;at least one&lt;/em&gt; of the child model associated. Easy enough, right?&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;So, let&amp;rsquo;s say you have a model, and a has_many relationship to another model. You want to accept nested attributes for the child models in your forms, and you also want to validate that the children must be present; the parent model can&amp;rsquo;t be saved unless it has &lt;em&gt;at least one&lt;/em&gt; of the child model associated. Easy enough, right?&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
class Parent &lt; ActiveRecord::Base
  has_many :children
  
  accepts_nested_attributes_for :children, :allow_destroy =&gt; true
  
  validates_presence_of :children
end

class Child &lt; ActiveRecord::Base
  belongs_to :parent
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;That&amp;rsquo;s not too bad. But the thing is, this will validate presence of the children on create, but not on update&amp;hellip;&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&gt;&gt; p = Parent.new # note: no children
=&gt; #&amp;lt;Parent id:nil ... &gt;
&gt;&gt; p.save!
=&gt; # errors glaore
&gt;&gt; p2 = Parent.find(:last)
=&gt; #&amp;lt;Parent id:23 ... &gt;
&gt;&gt; p2.update_attributes("childen_attributes" =&gt; {"0" =&gt; {:_destroy =&gt; 1}, [... etc. Assume all children are sent a destroy flag here]})
=&gt; true # what! it saved?
&gt;&gt; p2.valid?
=&gt; false # what! it's saved, but not valid anymore... (because it has no children)
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;So, the trouble is (I think), when you save the existing Parent, at the moment validation is checked, there are still children. They won&amp;rsquo;t be deleted until .save is called. So the object is valid. Then after it&amp;rsquo;s saved, the children have been deleted, and the object is saved, but it is no longer valid. What to do?&lt;/p&gt;

&lt;p&gt;Well, after some pondering, I wound up with this (in the update method):&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
class ParentsController &lt; ApplicationController
  # other methods...
  
  def update
    @parent = Parent.find(params[:id])
    
    # assign the attributes _without trying to save_
    @parent.attributes = params[:parent]
    
    # this line winds up as true if all items are marked for deletion; otherwise, false
    reject = @parent.children.inject(true){|truthiness, n| !!(truthiness &amp;&amp; n.marked_for_destruction?) }
    
    # check reject's truthiness first. Only try to save if reject is false. 
    # If we save first, it will save even though items will all be deleted.
    if !reject &amp;&amp; @parent.save(params[:order_form])
      flash[:notice] = "Object updated"
      redirect_to parent_path(@parent)
    else
      flash[:notice] = "Object could not be saved"
      render :action =&gt; :edit
    end
end
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Now, checking for an objects validity in the controller seems wrong to me, too, but it works. Anyone who has run into this find another way to do it?&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>xwing</title>
    <link href="http://philcrissman.com/2010/04/01/xwing" rel="alternate"/>
    <id>http://philcrissman.com/2010/04/01/xwing</id>
    <published>2010-04-01T00:00:00-07:00</published>
    <updated>2010-04-01T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/B0CsT.jpg" width="440" /&gt;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/B0CsT.jpg" width="440" /&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Oracle To Acquire Oracle</title>
    <link href="http://philcrissman.com/2010/04/01/oracle-to-acquire-oracle" rel="alternate"/>
    <id>http://philcrissman.com/2010/04/01/oracle-to-acquire-oracle</id>
    <published>2010-04-01T00:00:00-07:00</published>
    <updated>2010-04-01T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;REDWOOD SHORES &amp;mdash; Oracle is rumored to have lined up yet another in a long string of billion dollar acquisitions, and this time they have set their sights on their very own corporation. No one from Oracle has been willing to make an official statement regarding the rumors, but the news has been spreading throughout Silicon Valley&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;REDWOOD SHORES &amp;mdash; Oracle is rumored to have lined up yet another in a long string of billion dollar acquisitions, and this time they have set their sights on their very own corporation. No one from Oracle has been willing to make an official statement regarding the rumors, but the news has been spreading throughout Silicon Valley.&lt;/p&gt;

&lt;p&gt;Oracle, currently worth an estimated 47 billion USD, is a market leader in enterprise software, known particularly for their database product. Industry analysts admit that a corporation buying itself outright is unprecedented, but that, &amp;ldquo;As a strategic move, it makes a great deal of sense.&amp;rdquo; Enterprise consultant Robert Forsythe comments, &amp;ldquo;At this point, there are not a whole lot of other companies for Oracle to acquire. Purchasing themselves provides a creative way around this dilemma. Also, adding Oracle&amp;rsquo;s stellar sales staff to their already exhaustive line of software products is sure to be a winning combination.&amp;rdquo; Forsythe added, &amp;ldquo;I would predict that the shareholders will be happy to hear this rumor confirmed in the near future.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Not all industry analysts are quite so certain. &amp;ldquo;Rumors fly all over Silicon Valley on a regular basis,&amp;rdquo; said veteran Valley analyst Pratik Singh. &amp;ldquo;This is just the latest in a long line of the same. Could Oracle buy Oracle? Well, sure they could. They certainly have the capital to do so, and are in a better position than anyone else to know the details of Oracle&amp;rsquo;s business and strategy. But I fear this will only end up much like last year&amp;rsquo;s rumored acquisition of software giant Microsoft, by software giant Microsoft. That had everyone&amp;rsquo;s heads turning as well.&amp;rdquo; Pratik added, &amp;ldquo;Of course, no one in the press bothered to pay attention to the fact that this would have been a terrible acquisition.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;When questioned about the apparent contradiction inherent to the rumors, Forsythe said, &amp;ldquo;Sure, industry outsiders might ask questions like, &lt;em&gt;why would Oracle buy themselves? Don&amp;rsquo;t they already own themselves?&lt;/em&gt;&amp;rdquo; Forsythe paused to allow himself a knowing chuckle. &amp;ldquo;But that just betrays a lack of understanding of how things work in the Valley.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Indeed, acquisitions in and around Silicon Valley have a long and convoluted history, especially Oracle&amp;rsquo;s own long list of corporate purchases. Just last year, Oracle announced a purchase of BEA Software, an announcement which was hastily retracted when it was discovered that Oracle had already purchased BEA Software the previous fiscal year.&lt;/p&gt;

&lt;p&gt;Even the skeptical Singh notes, &amp;ldquo;Oracle does have some of the brightest business minds in the world on their payroll. It would be irresponsible to assume that they have not considered the possibility of an acquisition of Oracle, by Oracle, and that they would not have made some detailed projections on the possible results of such a transaction. If they believed it would be a positive move for the shareholders, well, of course, every consideration would be made and Oracle would ultimately make the decision that is best for itself, it&amp;rsquo;s shareholders and its customers and other stakeholders.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Regardless of the many and varied opinions put forth by the industry pundits, the rumors continue to gain momentum, and Oracle&amp;rsquo;s stock price has indeed jumped several points by close of business yesterday as a result.&lt;/p&gt;

&lt;p&gt;Oracle&amp;rsquo;s CEO, Larry Ellison, also refused to comment directly on the rumors, saying only, &amp;ldquo;I&amp;rsquo;m Larry f@#$ing Ellison, I&amp;rsquo;ll buy whatever the f@#$ I want to,&amp;rdquo; before threatening members of the press corps with disembowelment at the hands of his samurai bodyguards.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Here Are The News</title>
    <link href="http://philcrissman.com/2010/03/23/here-are-the-news" rel="alternate"/>
    <id>http://philcrissman.com/2010/03/23/here-are-the-news</id>
    <published>2010-03-23T00:00:00-07:00</published>
    <updated>2010-03-23T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;This is simply awesome.&lt;/p&gt;

&lt;p&gt;&lt;object width="640" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/YtGSXMuWMR4&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en_US&amp;feature=player_embedded&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/YtGSXMuWMR4&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en_US&amp;feature=player_embedded&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="425" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;This is simply awesome.&lt;/p&gt;

&lt;p&gt;&lt;object width="640" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/YtGSXMuWMR4&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en_US&amp;feature=player_embedded&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/YtGSXMuWMR4&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en_US&amp;feature=player_embedded&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="425" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;

&lt;p&gt;Courtesy &lt;a href="http://misener.org/archives/618"&gt;Dan Misener&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Hello Toto</title>
    <link href="http://philcrissman.com/2010/02/28/hello-toto" rel="alternate"/>
    <id>http://philcrissman.com/2010/02/28/hello-toto</id>
    <published>2010-02-28T00:00:00-08:00</published>
    <updated>2010-02-28T00:00:00-08:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Moving this blog over to Toto. I did not move all the posts, but I don&amp;rsquo;t think there&amp;rsquo;s a big loss for the ones I neglected, and you can alway spend time looking for cached or archived pages if it Really Matters. Sorry&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Moving this blog over to Toto. I did not move all the posts, but I don&amp;rsquo;t think there&amp;rsquo;s a big loss for the ones I neglected, and you can alway spend time looking for cached or archived pages if it Really Matters. Sorry.&lt;/p&gt;

&lt;p&gt;Was having some trouble getting the feed to worked automagically, we&amp;rsquo;ll see what has happened there when it goes live.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dumb Results Can Be Better Than Smart Results</title>
    <link href="http://philcrissman.com/2010/02/18/dumb-results-can-be-better-than-smart-results" rel="alternate"/>
    <id>http://philcrissman.com/2010/02/18/dumb-results-can-be-better-than-smart-results</id>
    <published>2010-02-18T00:00:00-08:00</published>
    <updated>2010-02-18T00:00:00-08:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/find_x.jpg" alt="" title="find_x" width="394" /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;The last couple posts have crossed over into a couple really big topics; one is web application usability, the other is the quality of results returned by an algorithm. They are not the same topic. Anything that can be made more usable should be. The quality of an algorithm&amp;rsquo;s results are not necessarily related to that. I started chatting with &lt;a href="http://twitter.com/KuraFire"&gt;@Kurafire&lt;/a&gt; about this, and he is making some great points&amp;hellip; but I still don&amp;rsquo;t precisely agree&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/find_x.jpg" alt="" title="find_x" width="394" /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;The last couple posts have crossed over into a couple really big topics; one is web application usability, the other is the quality of results returned by an algorithm. They are not the same topic. Anything that can be made more usable should be. The quality of an algorithm&amp;rsquo;s results are not necessarily related to that. I started chatting with &lt;a href="http://twitter.com/KuraFire"&gt;@Kurafire&lt;/a&gt; about this, and he is making some great points&amp;hellip; but I still don&amp;rsquo;t precisely agree.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;&lt;a href="http://twitter.com/KuraFire/status/9266841104"&gt;The problem with Google's algorithm is that a "mere" blog could outweigh the second-most visited website on the planet.&lt;/a&gt;&lt;/blockquote&gt;




&lt;blockquote&gt;&lt;a href="http://twitter.com/KuraFire/status/9267865186"&gt;My point is that a site's traffic rank should be weighed more heavily, certainly when the difference btwn the two is so huge.&lt;/a&gt;&lt;/blockquote&gt;


&lt;p&gt;Let&amp;rsquo;s forget the &amp;ldquo;Facebook login&amp;rdquo; going to ReadWriteWeb rather than Facebook itself, for a moment. Let&amp;rsquo;s generalize.&lt;/p&gt;

&lt;p&gt;&lt;strong style="font-size:1.5em;"&gt;Question: should an article &lt;em&gt;about&lt;/em&gt; a company or entity &lt;em&gt;ever&lt;/em&gt; get a higher search ranking than the website of the company or entity itself?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you phrase it that way, I think the answer is clearly &lt;strong&gt;YES&lt;/strong&gt;, there are situations where that could and should happen.&lt;/p&gt;

&lt;p&gt;In late 2001, it would make a lot of sense for a search for &amp;ldquo;ENRON quarterly earnings&amp;rdquo; to point to an article about the accounting scandal rather than simply going straight to an official PDF of their earnings.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s reasonable that a search for &amp;ldquo;Amway&amp;rdquo; could return an article skeptical of MLMs as high or sometimes higher than the company&amp;rsquo;s own site.&lt;/p&gt;

&lt;p&gt;Not all the time, and not every time, but there are situations where an article about something could or should get a higher result than the thing itself.&lt;/p&gt;

&lt;p&gt;A human being organizing the results might never do that; or they would only do it after it became obvious. Algorithms are dumb. They will just spit out a result based on some sort of process. Sometimes, that&amp;rsquo;s better, since it removes our innate bias to how we think things should be ordered. If we try to weight an algorithm too much for the things we innately think should be on top, we could actually be detracting from the value of the algorithm.&lt;/p&gt;

&lt;p&gt;Just a thought. I&amp;rsquo;m by no means saying that the googorithm can do no wrong, or has no room for improvement. Just that it&amp;rsquo;s possible for dumb results to be better than &amp;ldquo;smart&amp;rdquo; results.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Why It's Not A Google Failure</title>
    <link href="http://philcrissman.com/2010/02/17/why-its-not-a-google-failure" rel="alternate"/>
    <id>http://philcrissman.com/2010/02/17/why-its-not-a-google-failure</id>
    <published>2010-02-17T00:00:00-08:00</published>
    <updated>2010-02-17T00:00:00-08:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;By far the most common and seemingly reasonable objections to my &lt;a href="/2010/02/16/no-were-not-the-stupid-ones"&gt;recent post&lt;/a&gt; about internet applications and users have been along these lines:&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;By far the most common and seemingly reasonable objections to my &lt;a href="/2010/02/16/no-were-not-the-stupid-ones"&gt;recent post&lt;/a&gt; about internet applications and users have been along these lines:&lt;/p&gt;

&lt;blockquote style="font-size: 1.5em;"&gt;Well, a ReadWriteWeb article about Facebook login is &lt;em&gt;certainly not the same&lt;/em&gt; as Facebook's actual login page. So if people are looking for Facebook's login page, using Google, and are getting to a blog post instead, Google has indeed failed them.&lt;/blockquote&gt;


&lt;p&gt;Guys, gals, listen. This sounds very reasonable. It sounds empathetic. It feels right.&lt;/p&gt;

&lt;p&gt;&lt;strong style="font-size: 3em;"&gt;It&amp;rsquo;s wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stop and think, for a second, what it means to hold the conclusion that Google has failed their users in this case. It would mean, first and foremost, that in an ideal world, &lt;strong style="font-size: 1.5em;"&gt;Google should never have returned any other result than the Facebook login page as a response to the query &amp;ldquo;facebook login.&amp;rdquo;&lt;/strong&gt; Okay; &lt;em&gt;if&lt;/em&gt; that were true, what does that mean? Either:&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Their algorithm is not good enough.&lt;/strong&gt; It's easy to say this, but let's remember that this algorithm that is "not good enough" is the same algorithm that catapulted a startup out of nowhere to complete domination in a field (search) that was well saturated by large successful search engines, even in the late 90s; this algorithm that is "not good enough," was nevertheless good enough to pull users away from every other established search engine.

In this case, for an algorithm to be "good enough" to anticipate this particular scenario, I think it would basically need to be fully fledged artificially intelligent. So great, good luck with that; have fun on the research staff at the major university of your choosing.

Also, I'd dare to suggest that if you can come up with a better algorithm, you have a corner office and a stack of VC money with your name on it waiting for you any time you want it, so get cracking.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Google should have anticipated this and manually set a top search result with the correct site for this query.&lt;/strong&gt; It seems that people actually think this; it seems outrageous and unthinkable to me. There's no way Google, or any other large service, could anticipate this. I mean, it would be insulting to even suggest it:

&lt;strong&gt;Engineer 1:&lt;/strong&gt; Wait... wait... what if people are searching for a website login, and they query that? We should make sure that it is returned as the first result. Otherwise they might go to another page and think that they are on their website, and they will be confused that they can't log in.
&lt;strong&gt;Engineers 2-999:&lt;/strong&gt; Wait, now, the users may not be technical, but they aren't &lt;em&gt;that&lt;/em&gt; clueless. 
&lt;strong&gt;Engineer 1:&lt;/strong&gt; But...
&lt;strong&gt;Engineers 2-999:&lt;/strong&gt; Man, are you ever condescending.
&lt;strong&gt;Engineer 1:&lt;/strong&gt; I just...
&lt;strong&gt;Engineers 2-999:&lt;/strong&gt; Why do you hate users so much?
&lt;strong&gt;Engineer 1:&lt;/strong&gt; But I'm just trying to help...
&lt;strong&gt;Engineers 2-999:&lt;/strong&gt; Come on, users are going to &lt;em&gt;know&lt;/em&gt; that they are not on the webpage they're looking for. It won't look the same. It'll have a different name. Unless it's a deliberate phishing scheme, and we are implementing this to detect and remove those... 
&lt;em&gt;(long technical discussion about programmatically detecting phishing sites begins)&lt;/em&gt;

Seriously, stop and think about it. You would need to be &lt;em&gt;horribly and resolutely cynical&lt;/em&gt; about the intelligence level of your users to even suggest, ahead of time, that they (for example) would mistake a blog post from a different website for a web application that they use regularly, possibly daily.

Besides that, there is an unwritten contract implied by Google's search listings. The fact that sponsored listings occur (reasonably clearly marked) at the top of the list, implies that the rest of the search results are &lt;em&gt;untampered&lt;/em&gt; with. They have been selected based on their relevance to the search query which you supplied. If Google can just select any old result at the top of the list, it completely destroys the credibility of the results.

&lt;em&gt;But wait,&lt;/em&gt; you might say. &lt;em&gt;They could do something along the same lines as the "Did you mean: [this]? that they already attempt to do for common mispellings..."&lt;/em&gt;. 

&lt;img src="http://philcrissman.com/images/posts/didyoumean.png" alt="" title="Screen shot 2010-02-16 at 10.49.12 PM" width="248" height="140" /&gt;
&lt;br /&gt;
&lt;small&gt;Oh, yeah, that *is* what I meant.&lt;/small&gt;&lt;br /&gt;

Yep, they could. And it's on this that I will concede, willingly, that perhaps they should try to do something like this in the future.

Where I disagree is the idea that they should have already been doing this; that they should have somehow (magically?) known that this would be necessary. 
&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;So there&amp;rsquo;s that. I&amp;rsquo;m not saying &lt;strong&gt;&amp;ldquo;Screw the users, let them figure it out! Survival of the fittest FTW&amp;rdquo;&lt;/strong&gt;. Really, I&amp;rsquo;m really not. Yes, absolutely, let&amp;rsquo;s make changes based on user behavior. Let&amp;rsquo;s make things easier to use when we find out they are not easy to use. Let&amp;rsquo;s do all those things.&lt;/p&gt;

&lt;p&gt;But let&amp;rsquo;s also say:&lt;/p&gt;

&lt;p&gt;It is okay to expect your users to have a basic understanding of the core functionality of your application. In the case of Google, this is not asking very much of the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google:&lt;/strong&gt; Okay, here&amp;rsquo;s how it works. You type something in the box.
&lt;strong&gt;User:&lt;/strong&gt; Okay, I&amp;rsquo;m typing.
&lt;strong&gt;Google:&lt;/strong&gt; &amp;hellip; and I&amp;rsquo;ll try to find anything on the whole entire internet that seems to match what you&amp;rsquo;re searching for, and I&amp;rsquo;ll give you a list.
&lt;strong&gt;User:&lt;/strong&gt; Great, so you&amp;rsquo;ll find exactly what I&amp;rsquo;m looking for.
&lt;strong&gt;Google:&lt;/strong&gt; .Well, not exactly&amp;hellip;. I&amp;rsquo;m going to find everything that &lt;em&gt;seems&lt;/em&gt; to match, and I&amp;rsquo;m going to give you a list, and here&amp;rsquo;s the thing, it might be a humongous list&amp;hellip;
&lt;strong&gt;User:&lt;/strong&gt; Awesome, so you will find exactly what I&amp;rsquo;m looking for.
&lt;strong&gt;Google:&lt;/strong&gt; &amp;hellip; well, I&amp;rsquo;ll tell you what, I&amp;rsquo;m going to put what I &lt;em&gt;think&lt;/em&gt; are the most relevant results near to the top of the list, okay, so chances are, hopefully&amp;hellip;
&lt;strong&gt;User:&lt;/strong&gt; Hey, that&amp;rsquo;s just what I was looking for. Thanks Google!
&lt;strong&gt;Google:&lt;/strong&gt; Yes, well. That did work out pretty nicely. Actually, I hope it works that well every time, but you should understand that I&amp;rsquo;m just giving you a list of what I &lt;em&gt;think&lt;/em&gt; will be the most relevant results, based on your query, and it might&amp;hellip; hello? Hello?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.overcompensating.com/posts/20100216.html"&gt;&lt;img src="http://philcrissman.com/images/posts/oc20100216.png" alt="" title="oc20100216" width="440"  /&gt;&lt;/a&gt;
&lt;small&gt;I used to have to log on to the internet uphill, both ways.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Listen, I understand that it&amp;rsquo;s challenging. I don&amp;rsquo;t actually think &amp;ldquo;non-technical&amp;rdquo; people are &amp;ldquo;stupid,&amp;rdquo; any more than a tailor would think a programmer was &amp;ldquo;stupid&amp;rdquo; for being bewildered when sat down in front of a state of the art sewing machine. But if I&amp;rsquo;m going to insist on using the sewing machine, the tailor will try to tell me how to use it. If I continue to try to use it incorrectly, the tailor will eventually want to give up on me, unless I&amp;rsquo;m able to grasp &lt;em&gt;at least&lt;/em&gt; the basic principles of how the thing works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Tailor:&lt;/strong&gt; &lt;em&gt;Look, it&amp;rsquo;s a sewing machine. See, here&amp;rsquo;s the bobbin&amp;hellip;&lt;/em&gt;
&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;I don&amp;rsquo;t really want a bobbin, I want thread. Or the needle. I think.&lt;/em&gt;
&lt;strong&gt;The Tailor:&lt;/strong&gt; &lt;em&gt;The thread is on the bobbin&amp;hellip; and it goes through the needle here&amp;hellip;&lt;/em&gt;
&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;And I push this pedal now?&lt;/em&gt;
&lt;strong&gt;The Tailor:&lt;/strong&gt; &lt;em&gt;No, no, not now! Ok, so here is where you set the sort of stitch you want &amp;mdash;&lt;/em&gt;
&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;I just want to sew these two pieces together. Won&amp;rsquo;t it just know what sort of stitch I want?&lt;/em&gt;
&lt;strong&gt;The Tailor:&lt;/strong&gt; &lt;em&gt;It&amp;rsquo;s just a machine, it doesn&amp;rsquo;t know anything. So we want this stitch here&amp;hellip;&lt;/em&gt;
&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;How would I know that? That&amp;rsquo;s easy for &lt;u&gt;you&lt;/u&gt; to do. Why does this have to be so hard?&lt;/em&gt;
&lt;strong&gt;The Tailor:&lt;/strong&gt; &lt;em&gt;If you&amp;rsquo;d just stop for a minute and learn to use it, it wouldn&amp;rsquo;t be that hard&amp;hellip;&lt;/em&gt;
&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;This all strange and unknown and mysterious and frightening and frustrating. Sewing sucks! The designers of this machine are stupid!&lt;/em&gt;
&lt;em&gt;(The Tailor gives up on me and goes to get a beer. I proceed to sew my index finger onto my jeans.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Funkatron, &lt;a href="http://funkatron.com/site/comments/were-the-stupid-ones-facebook-google-and-our-failure-as-developers/"&gt;whose post&lt;/a&gt; on this contributed to inspiring the original rant, added some points to the end of his post in response; and since he&amp;rsquo;s a smart guy, he &lt;em&gt;completely understands&lt;/em&gt; the point I was actually making (or attempting to make):&lt;/p&gt;

&lt;blockquote&gt;I certainly don&#8217;t think that the computer can become (anytime soon) a magic box that determines our whims, nor do I think that people shouldn&#8217;t have to learn some things.&lt;/blockquote&gt;


&lt;p&gt;This is the point exactly. If we really expect that Google should &amp;ldquo;just know&amp;rdquo; what we want, we are expecting it to be magical. We are asking for something that belongs to the realm of unicorns and rainbows with pots of gold at the end.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/unicorn.jpg" alt="" title="unicorn" width="259" height="300" style="margin:0px auto" /&gt;&lt;br /&gt;
&lt;small&gt;Magic Google Power!&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;At the risk of sounding like an asshole again, &lt;span style="font-size:1.5em;"&gt;it&amp;rsquo;s called a &lt;strong&gt;search engine&lt;/strong&gt;, not a &lt;strong&gt;finding engine&lt;/strong&gt;. It cannot read your mind. If you expect it to be able to read your mind, you are stepping outside the bounds of what can reasonably be expected from a machine. The famous button is &amp;ldquo;I&amp;rsquo;m &lt;strong&gt;feeling lucky&lt;/strong&gt;,&amp;rdquo; not &amp;ldquo;&lt;strong&gt;Take me to exactly the page I&amp;rsquo;m thinking about in my brain&lt;/strong&gt;.&amp;rdquo;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/pQHX-SjgQvQ&amp;hl=en_US&amp;fs=1&amp;rel=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/pQHX-SjgQvQ&amp;hl=en_US&amp;fs=1&amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;

&lt;h3&gt;Neither You, Nor Me, Nor Google, Can Read Minds&lt;/h3&gt;


&lt;p&gt;I&amp;rsquo;m married. Inevitably, my wife will say things or ask things, and lo and behold, &lt;em&gt;the thing that she really wants or means is not exactly the same thing as what she says&lt;/em&gt;. Ideally, I would &amp;ldquo;just know&amp;rdquo; what she &lt;strong&gt;intends&lt;/strong&gt; me to get from her comment or question. And while, over time (we&amp;rsquo;ve been married 8 &amp;frac12; great years), I can become a better guesser, &lt;strong style="font-size:1.3em;"&gt;I will never be 100% able to do this because&lt;/strong&gt; (surprise) &lt;strong style="font-size:1.3em;"&gt;I cannot read minds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the real point: &lt;strong style="font-size:1.5em;"&gt;if I view myself as a failure because of my inability to read minds, I am setting myself up for misery. It is not reasonable to set &lt;em&gt;impossible tasks&lt;/em&gt; as&lt;em&gt; criteria for success&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Really, if that one thing is not communicated in these most recent two posts, then I&amp;rsquo;m just not going to be able to communicate it. Expecting Google (or any software) to &amp;ldquo;know,&amp;rdquo; with certainty, my intentions, is completely absurd. And with that in mind, there is no way to call this a failure on the part of Google.&lt;/p&gt;

&lt;p&gt;Ed goes on to say:&lt;/p&gt;

&lt;blockquote&gt;What I do think is that the current interface modern OSes on computers provide is simply overwhelming for most users, to the point that it&#8217;s very challenging to learn how to accomplish tasks without a very significant investment of time.&lt;/blockquote&gt;


&lt;p&gt;Look, here I agree completely. I have agreed with this the whole time. I&amp;rsquo;m a huge supporter of user testing, of good UX design, and of changing things based on user feedback.&lt;/p&gt;

&lt;p&gt;In fact, I&amp;rsquo;m probably just being a bit pedantic to be stuck on this one, single atom of disagreement, that is, the idea that Google or developers generally have &amp;ldquo;failed.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s another example. When you go to a gas station to fill up your car (here in the US, at least), you can usually use a credit card at the pump to pay for your gas. A credit card has a magnetic stripe on one edge of one side of the card. So because I can flip a credit card upside down or front to back, there are four ways I can put the card into the slot, and only one way that the machine can read the magnetic stripe. Now, there is (almost) always a handy diagram showing you how you&amp;rsquo;re supposed to put the card into the machine. But people do it wrong all the time. Because the part of the card reader that reads the stripe is usually clear, there are normally only two obvious ways to insert the card: stripe up facing left, or stripe up facing right.&lt;/p&gt;

&lt;p&gt;Now, at some point, some wonderful person who designs these machines said, &lt;em&gt;You know what? People are always putting their card in the wrong way. It would be really trivial to just put a magnetic stripe reader on both sides, and then as long as the stripe is at the top, it is impossible to insert the card incorrectly.&lt;/em&gt; And they implemented it, and it seems to be standard on most new gas pumps.&lt;/p&gt;

&lt;p&gt;Is the new design, where it is (almost) impossible to run your card incorrectly, better? Absolutely it is. It&amp;rsquo;s improved.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/credit_card_swipe.jpg" alt="" title="credit_card_swipe" width="455" height="350" /&gt;&lt;br /&gt;
&lt;small&gt;Hey, now that&amp;rsquo;s pretty handy.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Was the old design wrong? Was it a failure on the part of the gas pump card reader designers? I&amp;rsquo;m going to say &lt;strong&gt;no&lt;/strong&gt;. It wasn&amp;rsquo;t wrong. It did what it was supposed to do, and asked only that the user glance at the diagram to know which way to put the stripe in to the card reader. There was room for improvement, and it was indeed improved, but it was not &amp;ldquo;wrong.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Steve Krug&amp;rsquo;s disciples might now be saying, &lt;em&gt;The old design &lt;strong&gt;requires&lt;/strong&gt; you to think, so it &lt;strong&gt;is&lt;/strong&gt; failing! Don&amp;rsquo;t make people think!&amp;ldquo;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Steve Krug&amp;rsquo;s work is great, and I agree completely with the &amp;ldquo;&lt;a href="http://www.amazon.com/gp/product/0321344758?ie=UTF8&amp;tag=idepermin-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0321344758"&gt;Don&amp;rsquo;t Make Me Think&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=idepermin-20&amp;l=as2&amp;o=1&amp;a=0321344758" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&amp;rdquo; mantra. But there comes a point, with anything, at which people must make a decision, and &lt;strong&gt;we have to assume that people will demonstrate some common sense&lt;/strong&gt;.&lt;/p&gt;

&lt;div style="width: 435px;"&gt;
&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/H3Byf8U1btI&amp;hl=en_US&amp;fs=1&amp;rel=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/H3Byf8U1btI&amp;hl=en_US&amp;fs=1&amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;p class="wp-caption-text"&gt;The machine knows where it is going!&lt;/p&gt;
&lt;/div&gt;


&lt;p&gt;&lt;small&gt;&lt;a href="http://www.wired.com/gadgetlab/2008/07/gps-causes-3000/"&gt;Wired claims that 300,000 accidents&lt;/a&gt; in the UK have been caused by people following their GPS systems&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;So you can only take that so far.&lt;/p&gt;

&lt;p&gt;If I want to sew, I can argue all day that sewing machines should be easier to use, and hey &amp;mdash; maybe we can still come up with ways to improve their usability. But sooner or later, I need to accept that &lt;strong&gt;I must learn to use a sewing machine in order to get the results that I want&lt;/strong&gt;. The responsibility is mine. It is not the sewing machine&amp;rsquo;s fault if I can&amp;rsquo;t stitch two things together.&lt;/p&gt;

&lt;p&gt;And if I blame the sewing machine, &lt;strong&gt;I&amp;rsquo;m wrong&lt;/strong&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>No, We're Not The Stupid Ones</title>
    <link href="http://philcrissman.com/2010/02/16/no-were-not-the-stupid-ones" rel="alternate"/>
    <id>http://philcrissman.com/2010/02/16/no-were-not-the-stupid-ones</id>
    <published>2010-02-16T00:00:00-08:00</published>
    <updated>2010-02-16T00:00:00-08:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Update: follow up post on &lt;a href="/2010/02/17/why-its-not-a-google-failure"&gt;why it&amp;rsquo;s not a Google failure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/wrong-mike.jpg" alt="From http://icanhascheezburger.com/2007/04/28/youre-doing-it-wrong-2/" title="doing-it-wrong" width="440" class="center size-full wp-image-2094" /&gt;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Update: follow up post on &lt;a href="/2010/02/17/why-its-not-a-google-failure"&gt;why it&amp;rsquo;s not a Google failure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/wrong-mike.jpg" alt="From http://icanhascheezburger.com/2007/04/28/youre-doing-it-wrong-2/" title="doing-it-wrong" width="440" class="center size-full wp-image-2094" /&gt;&lt;/p&gt;

&lt;p&gt;If you follow the same flow of information I do, you probably saw the article &lt;a href="http://www.lastpodcast.net/2010/02/10/facebook-login-is-hard-welcome-to-idiocracy/"&gt;Facebook login is hard&lt;/a&gt;, or are at least aware of the confusion it&amp;rsquo;s talking about. Just in case, for context: last week &lt;a href="http://www.readwriteweb.com/archives/facebook_wants_to_be_your_one_true_login.php"&gt;a ReadWriteWeb article&lt;/a&gt; became the top-listed result on Google for &amp;ldquo;Facebook Login&amp;rdquo;, and several hundred (just going off the number of comments) Facebook users wound up at ReadWriteWeb trying unsuccessfully to log in to facebook, eventually leaving comments venting their frustration. &lt;em&gt;(Aside: my favorite was the one who found the &amp;ldquo;right&amp;rdquo; way to get to facebook, now: search for it on Bing instead&amp;hellip;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But I&amp;rsquo;ve started seeing comments and blog posts to the effect that &lt;strong&gt;this is actually a failure on the developers part&lt;/strong&gt;; that bad UI or bad software/UX design is somehow &lt;em&gt;responsible&lt;/em&gt; for this.&lt;/p&gt;

&lt;p&gt;To which I say, &lt;span style="font-size:3.5em;font-weight:bold;"&gt;bullshit.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m a big fan of making things that have great user experience, intuitive UI, well developed information architecture, etc, etc. So I empathize with that line of thinking, to a point; yes, if there&amp;rsquo;s a city intersection that gets 500% more traffic accidents than every other intersection, maybe we should look at the urban planners and suggest they might have screwed it up and should now fix it. I don&amp;rsquo;t find this analogous to that, though.&lt;/p&gt;

&lt;p&gt;Not (for example) with this:&lt;/p&gt;

&lt;blockquote&gt;Isn't this really a failure of Google? (From &lt;a href="http://funkatron.com/site/comments/were-the-stupid-ones-facebook-google-and-our-failure-as-developers/"&gt;We're the stupid ones&lt;/a&gt;)&lt;/blockquote&gt;


&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/bush_doing_it_wrong.jpg" alt="" title="bush_doing_it_wrong" width="150" height="150" align="right" style="margin-left: 5px;"  /&gt;No. &lt;em&gt;&lt;strong&gt;It&amp;rsquo;s not a failure of Google&lt;/strong&gt;&lt;/em&gt;. &lt;strong&gt;RWW wrote an article about Facebook Connect &amp;mdash; about logging in with Facebook &amp;mdash; and said article became a top result for the phrase &amp;ldquo;Facebook login&amp;rdquo; on Google.&lt;/strong&gt; That is an example of Google &lt;em&gt;working as it is intended to work&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I think it&amp;rsquo;s fine if people use a search engine field as a sort of web-based CLI; heck I use it for that, if I&amp;rsquo;m looking for a site and don&amp;rsquo;t remember if it&amp;rsquo;s &lt;em&gt;.com&lt;/em&gt; or &lt;em&gt;.net&lt;/em&gt; or &lt;em&gt;.info&lt;/em&gt;, or if it&amp;rsquo;s &lt;em&gt;somethingapp.com&lt;/em&gt; or &lt;em&gt;somethinghq.com&lt;/em&gt; or &lt;em&gt;getsomething.com&lt;/em&gt;, and hey, if I &lt;strong&gt;know&lt;/strong&gt; that it&amp;rsquo;ll come up if I simply search for it, then yes: why not. Search is quicker than having to try even one extra URL because the first one you used the wrong TLD. So using a search engine to find your website: fine, go for it. I&amp;rsquo;m not arguing that this should be discouraged. &lt;em&gt;(That said, I believe there have been studies showing that people actually also search for fully qualified URLs, like &amp;ldquo;myspace.com,&amp;rdquo; and really, it does seem like someone should tell those folks about the address bar&amp;hellip; but I digress.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Facebook evidently has somewhere in the neighborhood of a bazillion users, now. I don&amp;rsquo;t want to stop and look it up, so lets just say it&amp;rsquo;s one bazillion, where &lt;code&gt;100 million &amp;lt; 1 bazillion &amp;lt; infinity&lt;/code&gt;; in that neighborhood somewhere. So the several hundred confused and frustrated users were something along the lines of a fraction of a rounding error on a percentage point of Facebook&amp;rsquo;s entire user base. Not what I would call a UI catastrophe.&lt;/p&gt;

&lt;p&gt;This is not to say that these people are not important, only that it is okay to expect them to learn how to use the internet. &lt;span style="font-size:1.5em;font-weight:bold;"&gt;It is okay to expect people to invest a little time to learn how stuff works and to retain an adequate portion of that education.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Just because it&amp;rsquo;s photoshopped doesn&amp;rsquo;t mean it&amp;rsquo;s not funny.&lt;/small&gt;&lt;img src="http://philcrissman.com/images/posts/elephants-larger-than-the-moon.jpg" alt="" title="elephants-larger-than-the-moon" width="440" class="aligncenter size-full wp-image-2101" /&gt;&lt;/p&gt;

&lt;p&gt;Take ReadWriteWeb. I don&amp;rsquo;t know if they&amp;rsquo;d win an &lt;em&gt;award&lt;/em&gt; for UI or UX, but they don&amp;rsquo;t suck. I think that it&amp;rsquo;s fairly clear that ReadWriteWeb is a distinct website named &lt;em&gt;ReadWriteWeb&lt;/em&gt;. I don&amp;rsquo;t think we should have expected them to introduce a flashing banner warning visitors: ATTENTION &amp;mdash; THIS SITE IS NOT ACTUALLY FACEBOOK. They wrote an article, that article got some google juice. All in all, they&amp;rsquo;re doing what they set out to do, writing stuff that is findable to the people who are looking for it.&lt;/p&gt;

&lt;p&gt;Taking an event like this one and suggesting that it is somehow the fault of the designers of Google and/or developers generally, is absurd. It just &lt;em&gt;isn&amp;rsquo;t&lt;/em&gt;. I empathize with some of what folks are saying (Funkatron, linked above, for example). If they just want to say &lt;em&gt;maybe we&amp;rsquo;re being too hard on people&lt;/em&gt;, I could grant a &lt;em&gt;well maybe&lt;/em&gt;, but overall, look:&lt;/p&gt;

&lt;p&gt;&lt;span style="font-size: 1.5em;font-weight:bold;"&gt;If I search for &amp;ldquo;basecamp&amp;rdquo; in Google and wind up at a mountain climbing equipment supply store instead of the 37signals product I wanted, &lt;u&gt;it is not &lt;em&gt;Google&lt;/em&gt;&amp;rsquo;s fault&lt;/u&gt; (or 37signals', or the camping store&amp;rsquo;s) if I start banging my head against the screen and asking &amp;ldquo;Wheerre are my prooooojectsssss?????&amp;rdquo;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It just isn&amp;rsquo;t.&lt;/p&gt;

&lt;p&gt;Update: follow up post on &lt;a href="/2010/02/17/why-its-not-a-google-failure"&gt;why it&amp;rsquo;s not a Google failure&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Fledgling Freelance Professor</title>
    <link href="http://philcrissman.com/2009/08/20/a-fledgling-freelance-professor" rel="alternate"/>
    <id>http://philcrissman.com/2009/08/20/a-fledgling-freelance-professor</id>
    <published>2009-08-20T00:00:00-07:00</published>
    <updated>2009-08-20T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;blockquote&gt;[_why] is a fledgling freelance professor, one who will die young and make no lasting impression. except there was that time when i vacuumed all of Greenland for them.&lt;br /&gt;&lt;em&gt;bio from the blog that formerly lived at whytheluckystiff.net&lt;/em&gt;&lt;/blockquote&gt;

</summary>
    <content type="html">&lt;blockquote&gt;[_why] is a fledgling freelance professor, one who will die young and make no lasting impression. except there was that time when i vacuumed all of Greenland for them.&lt;br /&gt;&lt;em&gt;bio from the blog that formerly lived at whytheluckystiff.net&lt;/em&gt;&lt;/blockquote&gt;




&lt;blockquote&gt;Unit testing, in particular, is designed to reel in spontaneous hacking. It is like framing a picture before it has been painted. Hacking, at heart, will continue to be something of spontaneous order, something of anarchy, and the landscape of hacking is something which comes from human action but is not of human design.&lt;br /&gt;&lt;em&gt;From "This Hack was not properly planned," quoted on &lt;a href="http://anarchaia.org/archive/2007/12/25.html"&gt;Anarchaia&lt;/a&gt;&lt;/em&gt;&lt;/blockquote&gt;




&lt;blockquote&gt;
No, let's not have rules. I don't feel comfortable with having coding standards or any protocol on Camping. The point of Camping is to have very ugly, tricky code that goes against all the rules that people make for "beautiful" code these days. To show that ugly code can do beautiful things, maybe.

I don't want to demonize anyone here, I just want to express the ideas that make Camping different. Camping's personality is 80x50. It is like the little gears of a watch that are all meshed together into a tight little mind-bending machine. The challenge of Camping isn't to figure out how to automate obfuscation. The challenge is to bring new tricks into the code that push Ruby's parser and make everyone look twice. Not all code needs to be a factory, some of it can just be origami.

_why
&lt;br /&gt;&lt;em&gt;From &lt;a href="http://kneath.tumblr.com/post/167536641/no-lets-not-have-rules-i-dont-feel"&gt;Kyle Neath's&lt;/a&gt; tumblr.&lt;/em&gt;
&lt;/blockquote&gt;


&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Why_the_lucky_stiff"&gt;Why the lucky stiff&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ejohn.org/blog/eulogy-to-_why/"&gt;John Resig&amp;rsquo;s eulogy to _why&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>script/console, Under The Hood</title>
    <link href="http://philcrissman.com/2009/07/24/scriptconsole-under-the-hood" rel="alternate"/>
    <id>http://philcrissman.com/2009/07/24/scriptconsole-under-the-hood</id>
    <published>2009-07-24T00:00:00-07:00</published>
    <updated>2009-07-24T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/3618515225_6446a9876b.jpg" /&gt;
Photo by &lt;a href="http://www.flickr.com/photos/steffe/"&gt;Steffe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve recently started digging into script/console a little deeper. As a tool for Rails development, I think it&amp;rsquo;s safe to say that words like &amp;ldquo;indispensable&amp;rdquo; come to mind when the topic of the console arises. That said, I&amp;rsquo;ve yet to see a really complete guide to using script/console &amp;mdash; lots and lots of collections of tips and tricks, but never a good solid guide to what&amp;rsquo;s going on with script/console&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;img src="http://philcrissman.com/images/posts/3618515225_6446a9876b.jpg" /&gt;
Photo by &lt;a href="http://www.flickr.com/photos/steffe/"&gt;Steffe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve recently started digging into script/console a little deeper. As a tool for Rails development, I think it&amp;rsquo;s safe to say that words like &amp;ldquo;indispensable&amp;rdquo; come to mind when the topic of the console arises. That said, I&amp;rsquo;ve yet to see a really complete guide to using script/console &amp;mdash; lots and lots of collections of tips and tricks, but never a good solid guide to what&amp;rsquo;s going on with script/console.&lt;/p&gt;

&lt;p&gt;This is the first of what will hopefully be several posts about what&amp;rsquo;s really going on when you open the rails console.&lt;/p&gt;

&lt;p&gt;If we look at just the console script, we&amp;rsquo;ll find just these three lines:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/plugin'
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;The first line is simply the shebang line that lets the file be an executable ruby script. The second line requires the file config/boot. This file is a little over a hundred lines by default, so we won&amp;rsquo;t reproduce it here; you can read it quickly (if you want to) in one of your own rails projects. It basically sets some load paths and some constants, and ends by booting rails with &lt;code&gt;Rails.boot!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The third line requires &lt;code&gt;commands/console&lt;/code&gt;&amp;hellip; and that&amp;rsquo;s it. So to see what&amp;rsquo;s actually happening, we&amp;rsquo;ll have to look there.&lt;/p&gt;

&lt;p&gt;You can find &lt;code&gt;commands/console.rb&lt;/code&gt; in &lt;code&gt;railties/lib&lt;/code&gt; in your rails directory, in &lt;code&gt;vendor&lt;/code&gt; if you have frozen rails to a specific version, or otherwise under your rails gem in the lib directory.&lt;/p&gt;

&lt;p&gt;(e.g., on this machine it&amp;rsquo;s in
 /usr/local/lib/ruby/gems/1.8/gems/rails/lib/commands/console.rb).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;console.rb&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'

require 'optparse'

options = { :sandbox =&gt; false, :irb =&gt; irb }
OptionParser.new do |opt|
  opt.banner = "Usage: console [environment] [options]"
  opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
  opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v }
  opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v }
  opt.parse!(ARGV)
end

libs =  " -r irb/completion"
libs &lt; &lt; %( -r "#{RAILS_ROOT}/config/environment")
libs &lt;&lt; " -r console_app"
libs &lt;&lt; " -r console_sandbox" if options[:sandbox]
libs &lt;&lt; " -r console_with_helpers"

if options[:debugger]
  begin
    require 'ruby-debug'
    libs &lt;&lt; " -r ruby-debug"
    puts "=&gt; Debugger enabled"
  rescue Exception
    puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'"
    exit
  end
end

ENV['RAILS_ENV'] = case ARGV.first
  when "p"; "production"
  when "d"; "development"
  when "t"; "test"
  else
    ARGV.first || ENV['RAILS_ENV'] || 'development'
end

if options[:sandbox]
  puts "Loading #{ENV['RAILS_ENV']} environment in sandbox (Rails #{Rails.version})"
  puts "Any modifications you make will be rolled back on exit"
else
  puts "Loading #{ENV['RAILS_ENV']} environment (Rails #{Rails.version})"
end
exec "#{options[:irb]} #{libs} --simple-prompt"
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;There&amp;rsquo;s a fair bit in there, so let&amp;rsquo;s look at what it&amp;rsquo;s doing in detail.&lt;/p&gt;

&lt;p&gt;Line 1 is setting a local variable named &lt;code&gt;irb&lt;/code&gt;. It checks to see if the constant &lt;code&gt;RAILS_PLATFORM&lt;/code&gt; matches a value that would indicate we&amp;rsquo;re using some flavor of Microsoft Windows; if we are, it sets &lt;code&gt;irb&lt;/code&gt; to &lt;code&gt;irb.bat&lt;/code&gt;, which is what irb will be named for a Windows build of ruby; otherwise it&amp;rsquo;s set to simply &lt;code&gt;irb&lt;/code&gt;, which is the commands name on *nix systems, including Mac OS X.&lt;/p&gt;

&lt;p&gt;Next it requires &amp;lsquo;optparse&amp;rsquo;. &lt;code&gt;optparse&lt;/code&gt; is a Ruby library for parsing options (I imagine you guessed that).&lt;/p&gt;

&lt;p&gt;Then a local variable named &lt;code&gt;options&lt;/code&gt; is created, and is given a few default parameters: &lt;code&gt;:sandbox&lt;/code&gt; is set to false (more on this in a moment), and &lt;code&gt;:irb&lt;/code&gt; is set to the local variable irb (in other words, to either &amp;lsquo;irb.bat&amp;rsquo; or &amp;lsquo;irb&amp;rsquo;, depending on the result of the expression on line 1).&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;OptionsParser&lt;/code&gt; object is created next. We won&amp;rsquo;t dive into the details of this, but you&amp;rsquo;ll note a striking similarity to what you see in this block and what you&amp;rsquo;ll see if you type &lt;code&gt;script/console -h&lt;/code&gt; in your rails root.&lt;/p&gt;

&lt;p&gt;So if we follow along, we&amp;rsquo;ll read about the three standard command line arguments we can use when firing up the console:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;mdash;sandbox&lt;/code&gt;, which just adds the feature that any changes you make to the database will be undone at the end of your console session
&lt;code&gt;&amp;mdash;irb&lt;/code&gt;, which allows you to choose a different version of irb if applicable; so, if you have Ruby 1.9 installed, but not set as your default ruby version, you could start up the console with &lt;code&gt;script/console &amp;mdash;irb=irb1.9&lt;/code&gt;, and see how your console experiments work with Ruby 1.9.
&lt;code&gt;&amp;mdash;debugger&lt;/code&gt;, which enables ruby debugging.&lt;/p&gt;

&lt;p&gt;Next a local variable named &lt;code&gt;libs&lt;/code&gt; is created; it&amp;rsquo;s a string, and a number of lines are concatenated to it, each in the form &amp;ldquo; -r [some library or module]&amp;rdquo;. The libs variable is eventually going to be passed to irb when the console starts it; the -r switch to irb simple requires whatever the next argument is. So this is simply building a list of the modules and libraries which are going to be present when the console is fired up.&lt;/p&gt;

&lt;p&gt;The next section handles the case where you have actually typed &lt;code&gt;script/console &amp;mdash;debugger&lt;/code&gt;; it tries to require ruby-debug, and if an exception is raised, it will helpfully suggest that you run &lt;code&gt;gem install ruby-debug&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On line 31, console sets the environment; it looks at your first argument to see if you tried to specify an environment, and if not, sets it to either &lt;code&gt;ARGV.first&lt;/code&gt; (the first argument, if applicable), &lt;code&gt;ENV[&amp;lsquo;RAILS_ENV&amp;rsquo;]&lt;/code&gt; (whatever the environment is already set to), or as a last resort to &amp;lsquo;&lt;code&gt;development&lt;/code&gt;&amp;rsquo; (which is probably what you want, most of the time, hence why you may only rarely use this feature).&lt;/p&gt;

&lt;p&gt;If you try this by typing &lt;code&gt;script/console foo&lt;/code&gt;, you&amp;rsquo;ll see that console will try (and fail, unless you&amp;rsquo;ve created a foo environment) to find the file &lt;code&gt;/config/environments/foo.rb&lt;/code&gt;. So as long as the environment you specify exists, the console will use it.&lt;/p&gt;

&lt;p&gt;Now, since it&amp;rsquo;s using &lt;code&gt;ARGV.first&lt;/code&gt;, you might ask yourself why, if you type &lt;code&gt;script/console &amp;mdash;sandbox&lt;/code&gt;, the console does not try to load the &amp;ldquo;&lt;code&gt;&amp;mdash;sandbox&lt;/code&gt;&amp;rdquo; environment. Good question! The answer can be found up in line 11: &lt;code&gt;opt.parse!(ARGV)&lt;/code&gt;. The &lt;code&gt;parse!&lt;/code&gt; method parses destructively; it pulls any valid options out of &lt;code&gt;ARGV&lt;/code&gt;, and then returns whatever&amp;rsquo;s left over. So if &lt;code&gt;ARGV&lt;/code&gt; started out as &lt;code&gt;&amp;ldquo;test &amp;mdash;sandbox &amp;mdash;irb=irb1.9&amp;rdquo;&lt;/code&gt;, after &lt;code&gt;opts.parse!(ARGV)&lt;/code&gt; it will just equal &lt;code&gt;&amp;ldquo;test&amp;rdquo;&lt;/code&gt;. If nothing but valid options were supplied (i.e., no attempt to specify an environment), ARGV would be an empty string, and the environment will be set to either &lt;code&gt;ENV[&amp;lsquo;RAILS_ENV&amp;rsquo;&lt;/code&gt;], if it exists, or to &amp;lsquo;development&amp;rsquo; if it doesn&amp;rsquo;t.&lt;/p&gt;

&lt;p&gt;So now console&amp;rsquo;s figured out which environment to use, it checks to see if you&amp;rsquo;ve specified the sandbox option, and if you have, it prints a friendly message to remind you that anything you do to the database will be undone when you exit the console.&lt;/p&gt;

&lt;p&gt;But wait, you might say. Other than print a message, it doesn&amp;rsquo;t do anything; what actually makes the sandbox/database rollback work? Good question. If you look back up at lines 14-18, where the libs variable is set, you&amp;rsquo;ll note that &lt;code&gt;console_sandbox&lt;/code&gt; is required, but &lt;em&gt;only if&lt;/em&gt; &lt;code&gt;options[:sandbox]&lt;/code&gt; returns true. &lt;code&gt;console_sandbox&lt;/code&gt; will take care of all that database rollback headache for us; so that&amp;rsquo;s where it will come from.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s only one line left: an &lt;code&gt;exec&lt;/code&gt; expression. exec is going to execute the string you pass to it on the command line. So a plain vanilla run of script/console is actually running:&lt;/p&gt;

&lt;pre&gt;
&lt;code  class="ruby"&gt;
irb -r irb/completion -r ~/your_rails_project_path/config/environment -r console_app -r console_with_helpers --simple_prompt
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;If you really want to, you could just type all that every time you want to use the console, but I&amp;rsquo;m guessing you&amp;rsquo;ll stick with script/console.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re thinking there must be a little more to it than this, you&amp;rsquo;re right; you&amp;rsquo;ll remember that when &lt;code&gt;libs&lt;/code&gt; was created, the modules &lt;code&gt;console_app&lt;/code&gt; and &lt;code&gt;console_with_helpers&lt;/code&gt; were required. That may be what I write about next, but in the meantime, if you have Rails installed you can always just open those files up and see what&amp;rsquo;s in them.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Ruby's Object#send Can Call Private And Protected Methods</title>
    <link href="http://philcrissman.com/2009/06/26/rubys-objectsend-can-call-private-and-protected-methods" rel="alternate"/>
    <id>http://philcrissman.com/2009/06/26/rubys-objectsend-can-call-private-and-protected-methods</id>
    <published>2009-06-26T00:00:00-07:00</published>
    <updated>2009-06-26T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;&lt;a href="http://www.flickr.com/photos/xiaming/99206245/"&gt;&lt;img src="http://farm1.static.flickr.com/30/99206245_862bc5c93d.jpg?v=0" /&gt;&lt;/a&gt;
&lt;small&gt;Photo by &lt;a href="http://www.flickr.com/photos/xiaming/99206245/"&gt;xiaming&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;&lt;a href="http://www.flickr.com/photos/xiaming/99206245/"&gt;&lt;img src="http://farm1.static.flickr.com/30/99206245_862bc5c93d.jpg?v=0" /&gt;&lt;/a&gt;
&lt;small&gt;Photo by &lt;a href="http://www.flickr.com/photos/xiaming/99206245/"&gt;xiaming&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;One of the hallmarks of object oriented programming in most every implementation of it that I know of is the ability to designate certain methods as &amp;ldquo;private&amp;rdquo; or &amp;ldquo;protected&amp;rdquo;, thus keeping them from being called willy-nilly by any old script that wants to call them. Ruby also has this, of course, but interestingly enough it can be easily circumvented.&lt;/p&gt;

&lt;p&gt;I guess there are a few posts floating around about it, but I discovered it by accident playing around in irb this evening. I was reading David A. Black&amp;rsquo;s The Well Grounded Rubyist, where he mentions that you could send a message to a class either within the class definition itself, or by simply sending it to the class object like you&amp;rsquo;d send any other message:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
# The normal way to do it
class Thing
  message :whatever
end

# you could also do this
Thing.message(:whatever)
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;David mention&amp;rsquo;s attr_accessor in this context, so I thought I&amp;rsquo;d try that. Open &lt;code&gt;irb&lt;/code&gt;:&lt;/p&gt;

&lt;pre lang="ruby"&gt;
&gt;&gt; class Thing
?&gt; end
&gt;&gt; Thing.attr_accessor :name
NoMethodError: private method 'attr_accessor' called for Thing:Class
&lt;/pre&gt;


&lt;p&gt;Oh. So much for that, then. But, knowing of the existence of the send method, I thought I&amp;rsquo;d try that.&lt;/p&gt;

&lt;pre lang="ruby"&gt;
Thing.send(:attr_accessor, :name)
=&gt; nil
&lt;/pre&gt;


&lt;p&gt;For the non-&lt;code&gt;irb&lt;/code&gt; user, that &lt;code&gt;nil&lt;/code&gt; that was returned, and the fact that no error message was returned, indicated that our experiment worked. Now &lt;code&gt;Thing&lt;/code&gt;&amp;rsquo;s have a name attribute.&lt;/p&gt;

&lt;pre lang="ruby"&gt;
&gt;&gt; t = Thing.new
&gt;&gt; t.name = "Larry"
=&gt; "Larry"
&gt;&gt; t.name
=&gt; "Larry"
&lt;/pre&gt;


&lt;p&gt;What&amp;rsquo;s interesting about all this is that &lt;code&gt;attr_accessor&lt;/code&gt; is a private method on &lt;code&gt;Class&lt;/code&gt;. Yet we just called it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;send&lt;/code&gt; is often introduced as a way to show how everything is an object and that you can do exciting things like &lt;code&gt;1.send(:+, 1)&lt;/code&gt; and get &lt;code&gt;2&lt;/code&gt; as the result. No one usually mentions that it can be used to call private or protected methods from outside a given class.&lt;/p&gt;

&lt;p&gt;To make it clear what you could do here:&lt;/p&gt;

&lt;pre lang="ruby"&gt;
&gt;&gt; class Thing
?&gt;    def hello
?&gt;     puts "Hello, world!"
?&gt;   end
?&gt;   private
?&gt;     def private_hello
?&gt;       puts "Hello, privately."
?&gt;     end
?&gt; end
&gt;&gt; t = Thing.new
&gt;&gt; t.hello
Hello, world!
=&gt; nil
&gt;&gt; t.private_hello
NoMethodError: private method 'private_hello' called for ...
&gt;&gt; t.send(:private_hello)
Hello, privately.
=&gt; nil
&lt;/pre&gt;


&lt;p&gt;So, yes. You can do this, if you so choose. Please use your powers for good, and not for evil.&lt;/p&gt;

&lt;p&gt;Now &lt;em&gt;why&lt;/em&gt; this works, I can&amp;rsquo;t yet say, though I&amp;rsquo;m interested in learning, if there is a reason. Evidently there &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/7404"&gt;may have been some debate&lt;/a&gt; as to whether ruby 1.9 would still have this behavior, but as of this writing it does.&lt;/p&gt;

&lt;p&gt;Note: I did only a brief search, and it seems &lt;a href="http://www.google.com/search?client=safari&amp;rls=en-us&amp;q=ruby+send+method&amp;ie=UTF-8&amp;oe=UTF-8"&gt;this functionality is not unknown&lt;/a&gt;, though it still seems somewhat odd to me that such an easy way to sidestep the private/protected designation of methods exists.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Rails: Testing Your Floating Point Numbers</title>
    <link href="http://philcrissman.com/2009/04/17/rails-testing-your-floating-point-numbers" rel="alternate"/>
    <id>http://philcrissman.com/2009/04/17/rails-testing-your-floating-point-numbers</id>
    <published>2009-04-17T00:00:00-07:00</published>
    <updated>2009-04-17T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;You&amp;rsquo;re being a Good Software developer and diligently testing all your code, and lo and behold, you get this result to one of your tests:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;

</summary>
    <content type="html">&lt;p&gt;You&amp;rsquo;re being a Good Software developer and diligently testing all your code, and lo and behold, you get this result to one of your tests:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
1) Failure: ... &amp;lt;1.0&amp;gt; expected but was &amp;lt;1.0&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;An annoying problem with floats that might look and for all practical purposes be equal, but internally as stored by the computer are not &lt;em&gt;precisely&lt;/em&gt; equal.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;re probably using:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
assert_equal 1.0, a_value_expected_to_be_1.0
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Instead, use:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
assert_in_delta 1.0, a_value_expected_to_be_1.0, 0.000001
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Though, you may also want to ask yourself if you really need to be using floating point numbers; but assuming that you &lt;em&gt;do&lt;/em&gt; need them, &lt;code&gt;assert_in_delta&lt;/code&gt; will compensate for the annoying fact that floating point numbers might not actually be precisely what you expect them to be.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Testing Ajax Requests In Rails</title>
    <link href="http://philcrissman.com/2009/01/18/testing-ajax-requests-in-rails" rel="alternate"/>
    <id>http://philcrissman.com/2009/01/18/testing-ajax-requests-in-rails</id>
    <published>2009-01-18T00:00:00-08:00</published>
    <updated>2009-01-18T00:00:00-08:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Just figured out a test on which I spent far too long wondering why it wasn&amp;rsquo;t working. I kept coming back to it and trying something else, and it kept not working&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Just figured out a test on which I spent far too long wondering why it wasn&amp;rsquo;t working. I kept coming back to it and trying something else, and it kept not working.&lt;/p&gt;

&lt;p&gt;We have a form which submits to a create action by a remote_form_for; so, an Ajax request, in other words. The controller action just uses &lt;code&gt;render :update&lt;/code&gt; and replaces some HTML instead of redirecting. But in every other respect, it&amp;rsquo;s a POST to the controller, and is going to call :create. Easy, right?&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re using shoulda, and despite having a perfectly reasonable &lt;code&gt;post :create, :whatever_id =&gt; @thing.id, :our_model =&gt; { :stuff =&gt; &amp;ldquo;stuff&amp;rdquo; }&lt;/code&gt; in the setup, it wasn&amp;rsquo;t actually creating the item; shoulda&amp;rsquo;s handy &lt;code&gt;should_change &amp;ldquo;Thing.count&amp;rdquo;, :by =&gt; 1&lt;/code&gt; kept failing.&lt;/p&gt;

&lt;p&gt;I finally just started flipping through The Literature (in this case, the Rails Way&amp;rsquo;s chapter on testing), and happened to notice an off-hand remark that, in addition to methods for POST, PUT, GET, etc, there was an &lt;code&gt;xhr&lt;/code&gt; method, to simulate an XMHHttpRequest.&lt;/p&gt;

&lt;p&gt;Well.&lt;/p&gt;

&lt;p&gt;What I should have been writing, all along, was:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
xhr :post, :create, 
  :whatever_id =&gt; @thing.id, 
  :our_model =&gt; {:stuff =&gt; "stuff"}
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;It&amp;rsquo;s always the little things.&lt;/p&gt;

&lt;p&gt;Remember to read the literature.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>In Which I Am No Longer A Very Good Bachelor</title>
    <link href="http://philcrissman.com/2009/01/16/in-which-i-am-no-longer-a-very-good-bachelor" rel="alternate"/>
    <id>http://philcrissman.com/2009/01/16/in-which-i-am-no-longer-a-very-good-bachelor</id>
    <published>2009-01-16T00:00:00-08:00</published>
    <updated>2009-01-16T00:00:00-08:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;My wife has gone to Thailand for two weeks. So I&amp;rsquo;m on my own.&lt;/p&gt;

&lt;p&gt;I am, as they say, &amp;ldquo;batching it&amp;rdquo; for a couple weeks. This is usually understood to mean that I will wear the same underwear for two weeks, eat nothing but junk food, abandon cleaning the house, and play video games all night&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;My wife has gone to Thailand for two weeks. So I&amp;rsquo;m on my own.&lt;/p&gt;

&lt;p&gt;I am, as they say, &amp;ldquo;batching it&amp;rdquo; for a couple weeks. This is usually understood to mean that I will wear the same underwear for two weeks, eat nothing but junk food, abandon cleaning the house, and play video games all night.&lt;/p&gt;

&lt;p&gt;This isn&amp;rsquo;t working out so well.&lt;/p&gt;

&lt;p&gt;The video game thing isn&amp;rsquo;t happening. I look at my X-box (old one, not a 360) and think, &lt;em&gt;I could sit and play something for&amp;hellip; for, well for hours.&lt;/em&gt; But then I think, &lt;em&gt;But I&amp;rsquo;ve finished all the games I own. And I don&amp;rsquo;t really feel like replaying them yet, and I could go get a new used game, but I can&amp;rsquo;t think of anything I&amp;rsquo;d want to own, and really, is that responsible?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I tried to leave the dishes in the sink. Normally this is no problem. This week I keep looking at them and thinking, &lt;em&gt;Sheesh, it&amp;rsquo;s only going to take five more seconds to put it in the dishwasher.&lt;/em&gt; And the next thing I know, it&amp;rsquo;s in the dishwasher.&lt;/p&gt;

&lt;p&gt;I bought a huge bag of potato chips when I went grocery shopping. They are still sitting unopened on the kitchen table. Every time I look at them, I think, &lt;em&gt;Those sound good, but I should really eat some real food. Those aren&amp;rsquo;t very good for me.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have a strange compulsion to vacuum the rug. I can&amp;rsquo;t explain it, it&amp;rsquo;s just there.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve tried leaving my clothes on the floor when I change, but it just throws the whole room off. I have to put them in the hamper.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m beginning to think that I am no longer a very good bachelor.&lt;/p&gt;

&lt;p&gt;Oh, I can talk the talk. I can say I&amp;rsquo;ll eat cereal two meals a day, shower &amp;ldquo;later,&amp;rdquo; and stay up till 3am. Except that there are some leftovers to eat, and that sounds a little better. Or maybe pasta. Or a roast. With some potatoes and broccoli. And I will feel a lot better if I have a shower, and 3am&amp;hellip; man, I need to get up early, I can&amp;rsquo;t do that.&lt;/p&gt;

&lt;p&gt;So far, I have not shaved my face. I am counting that as a point for the &amp;ldquo;batching it&amp;rdquo; score.&lt;/p&gt;

&lt;p&gt;But for now, I should get back to work. And if I&amp;rsquo;m not going to open those potato chips, I think I should really take them off the kitchen table and put them in the pantry.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>I Hold Strong Opinions About The Placement Of Curly Braces</title>
    <link href="http://philcrissman.com/2009/01/14/i-hold-strong-opinions-about-the-placement-of-curly-braces" rel="alternate"/>
    <id>http://philcrissman.com/2009/01/14/i-hold-strong-opinions-about-the-placement-of-curly-braces</id>
    <published>2009-01-14T00:00:00-08:00</published>
    <updated>2009-01-14T00:00:00-08:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;I hold strong opinions about the placement of curly braces.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t care where K &amp;amp; R put them, I&amp;rsquo;ll put them wherever I want to put them. And don&amp;rsquo;t even start with the CSS files with the closing curly brace indented inline with the rules. Where did that come from?&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I hold strong opinions about the placement of curly braces.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t care where K &amp;amp; R put them, I&amp;rsquo;ll put them wherever I want to put them. And don&amp;rsquo;t even start with the CSS files with the closing curly brace indented inline with the rules. Where did that come from?&lt;/p&gt;

&lt;p&gt;It appears that I also hold strong opinions about indentation. Also, on whether or not a space should be left on the inside of opening and closing delimiters before the argument(s) they contain, where such delimiters are optional, whether or not they should be used, and whether or not text should wrap in the source listing, .&lt;/p&gt;

&lt;p&gt;I have strong opinions about choices of languages to use for programming. Although I will concede, probably grudgingly, that there are other languages which may be faster, more elegant, more efficient, or more popular than my favorite language(s), this will not alter my preference, and if pressed I will defend my language regardless of its perceived shortcomings. If nothing else, I will claim that my language is more fun, or some other reason for its superiority which has nothing to do with programming languages &lt;em&gt;per se&lt;/em&gt;. Furthermore, I will not accept the use of these same arguments if used to show that a different language is somehow superior to my favorite language or languages.&lt;/p&gt;

&lt;p&gt;I have a great respect for people who understand topics or concepts which I do not understand yet, but which I nevertheless place on a pedestal as pinnacles of programming wisdom.&lt;/p&gt;

&lt;p&gt;I have deeply held convictions about text editors. Really, it&amp;rsquo;s better not to talk about it. Just walk away.&lt;/p&gt;

&lt;p&gt;I am strongly attached to the frameworks and libraries which I approve of, and repulsed by the ones of which I do not approve. Large libraries which I like are &lt;em&gt;multifaceted&lt;/em&gt;, while the ones which I do not like are &lt;em&gt;bloated&lt;/em&gt;. Small libraries which I like are &lt;em&gt;elegant and efficient&lt;/em&gt;, while those which I do not like are &lt;em&gt;incomplete or trivial&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I have strong opinions about Operating Systems. People who are not using my favorite Operating System would be far more productive if they would simply &amp;ldquo;wake up&amp;rdquo; and get &amp;ldquo;real computers&amp;rdquo;. Brilliant people whom I respect but who nevertheless use other Operating Systems are exempt.&lt;/p&gt;

&lt;p&gt;We should talk about indentation some more. I hold opinions on whether said indentations should use spaces or tabs, and how many spaces they should use. They are only opinions. However, if you do not share them, you are probably wrong.&lt;/p&gt;

&lt;p&gt;When there is more than one way to do something, I will have an opinion on which is the best way to do it. This opinion is correct, although I may tell you that your way of doing it is fine also. &lt;em&gt;I am just being nice. Your way is retarded, slow, inefficient, insufficiently clever, unmaintainable, obfuscated or deprecated, pick two.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have opinions about software development methodologies. These opinions cover project management styles, agile methodologies, artifacts, modeling languages, and best practices. Projects which fail to do well invariably failed because they neglected an area which I feel very strongly about, and will describe to you in great detail if you show a sign you are interested.&lt;/p&gt;

&lt;p&gt;I am deeply attached to my preferred tool for source control management, which is better than your preferred tool for source control management, unless you happen to prefer the same one, in which case you are correct.&lt;/p&gt;

&lt;p&gt;I have a favorite computer acronym, a favorite obsolete piece of hardware, a favorite programming anecdote, joke, historical event, and aphorism. I have a favorite algorithm, meme, binary operator, ascii character and UTF entity. I have a favorite NP Complete problem, which is more interesting than your favorite NP Complete problem, even though they can both be shown to be reducible to a common problem, or even to each other.&lt;/p&gt;

&lt;p&gt;Despite my not yet having designed or created a killer app, I am convinced that I know why other apps have failed, and will not hesitate to share this knowledge if prompted. Despite having not run a multi-million dollar technology company, I know exactly what is wrong with the companies which are out there, and how they could be fixed.&lt;/p&gt;

&lt;p&gt;Just don&amp;rsquo;t ask me about politics or religion, now; I prefer not to be argumentative on the internet.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://xkcd.com/386/"&gt;&lt;img src="http://imgs.xkcd.com/comics/duty_calls.png" /&gt;&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Some Ruby &amp; Rails Tricks</title>
    <link href="http://philcrissman.com/2008/08/27/some-ruby-and-rails-tricks" rel="alternate"/>
    <id>http://philcrissman.com/2008/08/27/some-ruby-and-rails-tricks</id>
    <published>2008-08-27T00:00:00-07:00</published>
    <updated>2008-08-27T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;I certainly can&amp;rsquo;t claim to have &lt;em&gt;discovered&lt;/em&gt; these tips; but they&amp;rsquo;ve been pretty helpful to me. Maybe this will just make them a little easier to find for whoever is looking for them next&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I certainly can&amp;rsquo;t claim to have &lt;em&gt;discovered&lt;/em&gt; these tips; but they&amp;rsquo;ve been pretty helpful to me. Maybe this will just make them a little easier to find for whoever is looking for them next.&lt;/p&gt;

&lt;h3&gt;Getting A Collection's Index From Within a Partial&lt;/h3&gt;


&lt;p&gt;Lets say you&amp;rsquo;re passing a collection to a partial, but that somewhere in that partial you are interested in knowing which index you&amp;rsquo;re at. Do you need to implement a counter? Nope; there already is one. A collection passed to a partial implicitly creates a counter called &lt;code&gt;[partial_name]_counter&lt;/code&gt;. So, if you called with&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&lt; %= render :partial =&gt; 'thing', :collection =&gt; @a_few_of_my_favorite_things %&gt;
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;then in your partial, you could use:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
&lt; %= thing_counter %&gt;
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;to return the index as you plow through the collection. Life is good. Rails is looking out for you. (Hat tip to &lt;a href="http://gmarik.blogspot.com/2007/09/rails-collection-index-within-partial.html"&gt;GMarik&lt;/a&gt;, which is where I saw this one.)&lt;/p&gt;

&lt;h3&gt;Obtaining a Class name From a String&lt;/h3&gt;


&lt;p&gt;Today I found myself wanting to take a string, let&amp;rsquo;s say &lt;code&gt;&amp;ldquo;Thing&amp;rdquo;&lt;/code&gt;, and use it as a class name, &lt;code&gt;Thing&lt;/code&gt;. Again, it turns out this can be done. In Ruby, class names are constants, so you can do&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
str = "Thing" #=&gt; "Thing"
Kernel.const_get(str) #=&gt; Thing
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Hooray!&lt;/p&gt;

&lt;h3&gt;Make Finding Easier&lt;/h3&gt;


&lt;p&gt;Find yourself writing long, complicated find expressions in your code? There is a better way.&lt;/p&gt;

&lt;p&gt;Perhaps in your code&amp;hellip; maybe even in a view&amp;hellip; maybe you want to find all &lt;code&gt;Things&lt;/code&gt; that don&amp;rsquo;t belong to the current use, and which are flagged with some property, and you&amp;rsquo;re temped to write something like:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
Thing.find(:all, :conditions =&gt; ["user != ? and flag = true", current_user])
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;What we could do is put some &lt;code&gt;has_finder&lt;/code&gt;s in the Thing model, something like&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
class Thing &lt; ActiveRecord::Base
has_finder :exclude_user, lambda {|user| {:conditions =&gt; "things.user_id != #{user.id}"}
has_finder :with_flag, :conditions =&gt; "things.flag = true"
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Having done that, you could now replace that first bit with:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="ruby"&gt;
Thing.find(:all).with_flag.exclude_user(current_user)
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;It&amp;rsquo;s a little shorter, sure, but more importantly, when you read it, it just makes more sense. A completely new person coming to look at this line would have a good idea what it was doing without even looking in the model to see what the &lt;code&gt;has_finder&lt;/code&gt;s were doing.&lt;/p&gt;

&lt;h3&gt;Okay then&lt;/h3&gt;


&lt;p&gt;If you&amp;rsquo;ve spent any amount of time using rails, these probably aren&amp;rsquo;t new to you. Everything&amp;rsquo;s new at least &lt;em&gt;once&lt;/em&gt;, though, so hopefully these are helpful to someone.&lt;/p&gt;

&lt;p&gt;Other favorite ruby or rails tricks? Leave a comment! Heck, we&amp;rsquo;re not prejudiced, here, go ahead and comment with your favorite Python or Perl or [other language] tricks, too, if you like.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Clearing Form Fields With jQuery</title>
    <link href="http://philcrissman.com/2008/05/09/clearing-form-fields-with-jquery" rel="alternate"/>
    <id>http://philcrissman.com/2008/05/09/clearing-form-fields-with-jquery</id>
    <published>2008-05-09T00:00:00-07:00</published>
    <updated>2008-05-09T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;I used a little jQuery last night to clear some form fields. The basic idea was, there were a couple text inputs in the form for first and last name; rather than label the fields, I made the value of each form to be initially &amp;ldquo;First&amp;rdquo; and &amp;ldquo;Last&amp;rdquo; respectively&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I used a little jQuery last night to clear some form fields. The basic idea was, there were a couple text inputs in the form for first and last name; rather than label the fields, I made the value of each form to be initially &amp;ldquo;First&amp;rdquo; and &amp;ldquo;Last&amp;rdquo; respectively.&lt;/p&gt;

&lt;p&gt;Then I was requested to make it so that when the field was clicked on, the word &amp;ldquo;First&amp;rdquo; or &amp;ldquo;Last&amp;rdquo; (respectively) would disappear, so that you could then proceed to enter a value without needing to highlight and delete the existing value of the text field.&lt;/p&gt;

&lt;p&gt;It turns out that with jQuery, this is simple enough; let&amp;rsquo;s assume your field has the class &amp;ldquo;clearme&amp;rdquo;:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="javascript" line="1"&gt;
$(document).ready(function () {
  $('.clearme').focus(function() {
    $(this).val("");
  });
});
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;If you&amp;rsquo;re familiar with jQuery, you know that the wrapper &lt;code&gt;$(document).ready()&lt;/code&gt; simply waits until the page is finished loading, then executes the function you&amp;rsquo;ve passed to it. In this case, the function passed looks for an item of the class &amp;ldquo;clearme&amp;rdquo; and waits for that element to receive focus. When it does, it changes the value to &amp;ldquo;&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Simple enough&amp;hellip; but wait! Now if the user types in &amp;ldquo;Beauregard Charles Maurice&amp;rdquo; as a first name, if he inadvertently clicks on the text box again, his name will disappear. &lt;em&gt;He would need to type that all over again.&lt;/em&gt; What can be done?&lt;/p&gt;

&lt;p&gt;There may be multiple ways; but jQuery has a handy method called &amp;ldquo;one&amp;rdquo; which will execute an event &lt;em&gt;one time only&lt;/em&gt;, which sounds like just what we want. So we&amp;rsquo;d change the body of that inner function to look like:&lt;/p&gt;

&lt;pre&gt;
&lt;code class="javascript" line="1"&gt;
$('.clearme').one("focus", function() {
  $(this).val("");
});
&lt;/code&gt;
&lt;/pre&gt;

</content>
  </entry>
  <entry>
    <title>Blizzard Closes My Unused World Of Warcraft Account For Unclear Reasons</title>
    <link href="http://philcrissman.com/2006/09/25/blizzard-closes-my-unused-world-of-warcraft-account-for-unclear-reasons" rel="alternate"/>
    <id>http://philcrissman.com/2006/09/25/blizzard-closes-my-unused-world-of-warcraft-account-for-unclear-reasons</id>
    <published>2006-09-25T00:00:00-07:00</published>
    <updated>2006-09-25T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;So, this was in my inbox this morning:&lt;/p&gt;

&lt;blockquote style="text-align:left"&gt;
***Notice of Account Closure***

Greetings,

This is a notification regarding your World of Warcraft account.  Access to this account has been permanently disabled for exploitation of the World of Warcraft economy or for being associated to accounts which have been closed for intended exploitation.  While we try to be as lenient as possible in our assessments of the results of exploitation investigations, reoccurring trends in exploitative endeavors on your account have ultimately resulted in account closure&amp;hellip;

</summary>
    <content type="html">&lt;p&gt;So, this was in my inbox this morning:&lt;/p&gt;

&lt;blockquote style="text-align:left"&gt;
***Notice of Account Closure***

Greetings,

This is a notification regarding your World of Warcraft account.  Access to this account has been permanently disabled for exploitation of the World of Warcraft economy or for being associated to accounts which have been closed for intended exploitation.  While we try to be as lenient as possible in our assessments of the results of exploitation investigations, reoccurring trends in exploitative endeavors on your account have ultimately resulted in account closure.

As a result, this account will no longer be able to access any aspect of World of Warcraft.  This action has been taken in accordance with the Terms of Use (http://www.worldofwarcraft.com/legal/termsofuse.html) and our game policies (http://www.blizzard.com/support/wowgm/?id=agm01712p).  According to the World of Warcraft Terms of Use, to which all players agree when installing World of Warcraft, Section 3, Paragraph C [Rules Related to Game Play] states that you may not do anything that Blizzard Entertainment considers contrary to the "essence" of World of Warcraft.

Thank you for your time and understanding of our position in this matter.  Please feel free to contact us with any questions or concerns you may have.

Regards,

Account Administration
Blizzard Entertainment
www.WorldOfWarcraft.com
&lt;/blockquote&gt;


&lt;p&gt;Hmm. &lt;em&gt;Access to this account has been permanently disabled for exploitation of the World of Warcraft economy or for being associated to accounts which have been closed for intended exploitation.&lt;/em&gt;  That&amp;rsquo;s interesting.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s especially interesting considering I cancelled my subscription over a month ago since I simply &lt;em&gt;did not have time to play World of Warcraft&lt;/em&gt;. I&amp;rsquo;m fairly certain I have not logged on to any WoW server in well over two months, possibly longer.&lt;/p&gt;

&lt;p&gt;I was considering re-activating the subscription at some point, if and/or when I have more free time to play MMORPG-type games (I just like typing MMORPG) &amp;mdash; so this is a little annoying.&lt;/p&gt;

&lt;p&gt;I replied to them; hopefully they can explain exactly what it is about &lt;em&gt;NOT PLAYING&lt;/em&gt; that flags an account as &amp;ldquo;exploitative&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;UPDATE: Folks keep visiting this post, so I can only guess that this keeps happening to people, or that people are still trying to resolve it.&lt;/p&gt;

&lt;p&gt;In my own case, my World of Warcraft account is &lt;em&gt;still closed&lt;/em&gt;. The only means they will accept to re-open it, apparently, is for me to send them a fax (yes! a FAX) of my driver&amp;rsquo;s license. I don&amp;rsquo;t have a fax machine, nor a scanner most of the time, so I keep putting this off. I finally got around to doing it one day, and they replied that the incoming fax was too fuzzy and that I should scan my ID again and re-fax it.&lt;/p&gt;

&lt;p&gt;That was about a year ago. I haven&amp;rsquo;t bothered to re-fax it yet.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Emperor's New Web</title>
    <link href="http://philcrissman.com/2006/09/22/the-emperors-new-web" rel="alternate"/>
    <id>http://philcrissman.com/2006/09/22/the-emperors-new-web</id>
    <published>2006-09-22T00:00:00-07:00</published>
    <updated>2006-09-22T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;Once upon a time there was an emperor of a far country. In this country, the internet prospered and grew, and the web was used by many of the emperor&amp;rsquo;s subjects. The emperor himself was a web aficionado, and was a great patron of Internet and web related ventures in his empire&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;Once upon a time there was an emperor of a far country. In this country, the internet prospered and grew, and the web was used by many of the emperor&amp;rsquo;s subjects. The emperor himself was a web aficionado, and was a great patron of Internet and web related ventures in his empire.&lt;/p&gt;

&lt;p&gt;One day, two developers arrived at the palace, and asked if they could have an audience with the emperor. When pressed, they stated that their purpose was something mysterious to do with the web, in which they believed that the emperor would have great interest, but which they could not reveal to the porter unless he signed a NDA. The porter, knowing his majesty&amp;rsquo;s affinity for all things webby, immediately ushered them to the audience room.&lt;/p&gt;

&lt;p&gt;When the emperor learned of their presence, he immediately went to meet them, and to ask them what it was they wished to show him.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;We are working on a Whole New Web,&amp;rdquo; said the first.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;It will be the New New Internet,&amp;rdquo; said the other.&lt;/p&gt;

&lt;p&gt;The emperor raised an eyebrow.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;It will be more responsive&amp;hellip; more socially connected,&amp;rdquo; said the first.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;It will look fancier,&amp;rdquo; said the second. &amp;ldquo;Everything will be shiny and beautiful.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;It may have to stay in beta for awhile,&amp;rdquo; began the first.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Also &amp;mdash; it possesses the unique quality that only those users who &amp;lsquo;get it&amp;rsquo; &amp;mdash; users with &amp;lsquo;clue&amp;rsquo; &amp;mdash; will be able to see it,&amp;rdquo; said the second.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Yes,&amp;rdquo; said the first. &amp;ldquo;You will immediately be able to tell who are the best and brightest in your empire by how they react to the New New Internet.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;I&amp;rsquo;m interested,&amp;rdquo; said the emperor. &amp;ldquo;Tell you what; you can stay in the palace, and work on this.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;And so the two strangers began to work. For a long time, they worked in solitude, but eventually, after the emperor had signed up for their release notification mailing list several times, they announced that they were ready to show him the results of their labors.&lt;/p&gt;

&lt;p&gt;Extremely excited, the emperor rushed down to the development lab. There he sat down in anticipation in front of a computer, and one of the developers clicked a link, and their new site sprang to life.&lt;/p&gt;

&lt;p&gt;The emperor blinked.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Well,&amp;rdquo; said the first, &amp;ldquo;What do you think?&amp;rdquo;&lt;/p&gt;

&lt;p&gt;The emperor considered. Certainly, it was very pretty. All the colors were vivid, and there was an attractive design scheme to the whole page. The logo was very shiny. It had a transparent shiny badge that said &amp;ldquo;Beta&amp;rdquo; covering one corner of it. You could connect with other users of the site. It had tags. It had RSS feeds.&lt;/p&gt;

&lt;p&gt;But none of these were things that were new to his majesty the emperor.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Well,&amp;rdquo; he began.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Have you seen &lt;em&gt;this&lt;/em&gt;?&amp;rdquo; said the second, and he began clicking things.&lt;/p&gt;

&lt;p&gt;As he clicked, various bits of the page would fade in and out, and slide around, and expand and contract. It was very slick-looking, and while it was not a completely &lt;em&gt;common&lt;/em&gt; practice, the emperor was aware of how this was done, and that it had been possible to do things like this on web pages for some time.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;That is nice,&amp;rdquo; he admitted. &amp;ldquo;Well&amp;hellip;&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;As we mentioned,&amp;rdquo; said the first, &amp;ldquo;Only people who &amp;lsquo;get it&amp;rsquo;, netizens with &amp;lsquo;clue&amp;rsquo; are able to see the New New Web.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Anxiously, the second said, &amp;ldquo;You do &lt;em&gt;see it&lt;/em&gt;, don&amp;rsquo;t you?&amp;rdquo;&lt;/p&gt;

&lt;p&gt;At this point, the emperor was unwilling to say that he did not have &amp;ldquo;clue&amp;rdquo;, or that he did not &amp;ldquo;get it&amp;rdquo;, so he said, &amp;ldquo;Well of course I see it. It&amp;rsquo;s the new new web. I &amp;lsquo;get it&amp;rsquo;!&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Wonderful,&amp;rdquo; said the two developers in chorus. &amp;ldquo;We knew you would!&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Now we just need to share this with the rest of the empire,&amp;rdquo; said the first. &amp;ldquo;You will notice that you have several &amp;lsquo;invites&amp;rsquo; to share to our beta.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Perhaps after it has spread around we can talk about second round funding,&amp;rdquo; said the second.&lt;/p&gt;

&lt;p&gt;The emperor agreed, and dutifully &amp;ldquo;invited&amp;rdquo; some of his relatives and courtiers to the beta. He was sure to say that this was, indeed, &lt;em&gt;The New New Web&lt;/em&gt;, and that only those &amp;ldquo;with clue&amp;rdquo; could &amp;ldquo;get it.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Needless to say, all of his invitees gladly proclaimed that they, too, &amp;ldquo;get it&amp;rdquo;, and began to invite others to the Emperor&amp;rsquo;s New Web.&lt;/p&gt;

&lt;p&gt;All over the empire, everyone began to flock to the Emperor&amp;rsquo;s New Web, and everyone said they &amp;ldquo;got it,&amp;rdquo; and were not about to admit they did not have &amp;ldquo;clue.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;One day, they threw a New New Web Conference, and gathered together to talk about important things like well-styled XHTML, the use of gradients in company logos, tag clouds, and social networks. While the emperor himself was giving the keynote of the highlights of the New New Interweb, a young boy in the crowd proclaimed loudly:&lt;/p&gt;

&lt;p&gt;&amp;ldquo;But it&amp;rsquo;s just the same as the old web! There isn&amp;rsquo;t anything new at all!&amp;rdquo;&lt;/p&gt;

&lt;p&gt;There was an awkward pause, and then the crowd began to laugh. &amp;ldquo;Pay no attention to him,&amp;rdquo; they said. &amp;ldquo;He&amp;rsquo;s just a boy. He doesn&amp;rsquo;t &amp;lsquo;get it&amp;rsquo;.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Sure it&amp;rsquo;s shiny,&amp;rdquo; said the boy, &amp;ldquo;But shiny is not enough to call it a Whole New Web.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;It has social networking and tagging!&amp;rdquo; said someone.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Social networking is not new,&amp;rdquo; said the boy. &amp;ldquo;Bulletin boards are an example older as old as my parents. And surely &lt;em&gt;tags&lt;/em&gt; alone are not&amp;hellip; the Whole New Web?&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;It has Ajax and fancy JavaScript effects!&amp;rdquo; said someone else.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;And those&amp;hellip; programming languages and effects that are caught on but are not &amp;lsquo;new&amp;rsquo; at all &amp;mdash; those are all that you are calling the New New Web?&amp;rdquo; asked the boy.&lt;/p&gt;

&lt;p&gt;The emperor decided it was time to speak. &amp;ldquo;But it is the &lt;em&gt;combination&lt;/em&gt; of all these elements, together, that is new.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;The boy seemed perplexed. &amp;ldquo;Is it?&amp;rdquo; he asked.&lt;/p&gt;

&lt;p&gt;The emperor stammered. The crowd began to murmur and to look suspiciously at the emperor, and at the large plasma screen which displayed a page of the Emperor&amp;rsquo;s New Web.&lt;/p&gt;

&lt;p&gt;Suddenly, the emperor said, &amp;ldquo;Also, I would like to announce that I am providing first round venture capital for entrepreneurs who are developing applications for the New New Web!&amp;rdquo;&lt;/p&gt;

&lt;p&gt;At this, everyone in the crowd proclaimed, &amp;ldquo;Ah! Now we see it! There it is &amp;mdash; it&amp;rsquo;s the New New Interweb!&amp;rdquo; And they began to rush forward to display their Powerpoint presentations.&lt;/p&gt;

&lt;p&gt;And that is the story of the Emperor&amp;rsquo;s New Web.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Howto Add Your Xscreensavers To Gnome Screensaver</title>
    <link href="http://philcrissman.com/2006/07/25/howto-add-your-xscreensavers-to-gnome-screensaver" rel="alternate"/>
    <id>http://philcrissman.com/2006/07/25/howto-add-your-xscreensavers-to-gnome-screensaver</id>
    <published>2006-07-25T00:00:00-07:00</published>
    <updated>2006-07-25T00:00:00-07:00</updated>
    <author>
      <name></name>
    </author>
    <summary type="html">&lt;p&gt;The fully qualified directories in this particular &amp;ldquo;howto&amp;rdquo; are specific to SLED 10, and will undoubtedly be different on a different version of Linux&amp;hellip;&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;The fully qualified directories in this particular &amp;ldquo;howto&amp;rdquo; are specific to SLED 10, and will undoubtedly be different on a different version of Linux.&lt;/p&gt;

&lt;p&gt;Something you might notice on installing SLED 10 is that, like most distros which feature Gnome 2.12 or 2.14, xscreensaver has been partially or fully replaced by gnome-screensaver. In the case of SLED 10, xscreensaver was &lt;em&gt;installed&lt;/em&gt;, but none of its screensavers were available; gnome-screensaver listed only a scant five or six options.&lt;/p&gt;

&lt;p&gt;I spent some time tracking down how to make xscreensaver&amp;rsquo;s hacks available to gnome-screensaver, so here it is.&lt;/p&gt;

&lt;p&gt;Each screensaver, for both gnome-screensaver and xscreensaver, has a config file. So to move files from xscreensaver to gnome-screensaver, we need to move not only the screensaver programs themselves, but also the config files.&lt;/p&gt;

&lt;p&gt;Moving the screensavers is the easy part; all you&amp;rsquo;d need to do is:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;
cp -i /usr/lib/xscreensaver/* /opt/gnome/lib/gnome-screensaver/gnome-screensaver/
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;Yes, technically this code &lt;em&gt;copies&lt;/em&gt; the screensavers, not moves them&amp;hellip; but that&amp;rsquo;s okay. The -i switch is to make the process interactive; if any other the new screensavers has the same name as an existing one, it will as if you want to overwrite it, rather than just deciding for you. There should be only one such anomaly: popsquares. I chose not to overwrite it, as it works fine already and is probably exactly the same.&lt;/p&gt;

&lt;p&gt;Next, you need to move the config files. The only problem is, xscreensaver config files are .xml files, and gnome-screensaver files are .desktop files.&lt;/p&gt;

&lt;p&gt;It turns out that this is a problem with a ready made solution: our friends at Gnome have a script which will migrate our .xml files into .desktop files. For this to work, you&amp;rsquo;ll need 2 files:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://cvs.gnome.org/viewcvs/gnome-screensaver/data/migrate-xscreensaver-config.sh?rev=1.1&amp;view=log"&gt;migrate-xscreensaver-config.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://cvs.gnome.org/viewcvs/gnome-screensaver/data/xscreensaver-config.xsl?rev=1.1&amp;view=log"&gt;xscreensaver-config.xsl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just click the &amp;ldquo;download&amp;rdquo; links on the above two pages. I moved the two files to /opt/gnome/lib/gnome-screensaver/, but you can put them anywhere &amp;mdash; they just need to be in the same place.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll need to make migrate-xscreensaver-config.sh executable (it should go without saying, but you&amp;rsquo;ll need to execute the following command from whatever directory you put the files in):&lt;/p&gt;

&lt;pre&gt;
&lt;code class="code2"&gt;
# chmod +x migrate-xscreensaver-config.sh
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;That being done, all you&amp;rsquo;ll have left is:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;# cd /opt/gnome/share/gnome-screensaver/themes/
# /opt/gnome/lib/gnome-screensaver/migrate-xscreensaver-config.sh /etc/xscreensaver/*.xml
&lt;/code&gt;
&lt;/pre&gt;


&lt;p&gt;That&amp;rsquo;s that. You will find (at least on SLED 10) that you need to restart X &amp;mdash; just logging out of Gnome and back in should do it.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re attempting to use these steps on a different version of linux, you may need to use find or locate to figure out the proper file paths to use. Enjoy.&lt;/p&gt;
</content>
  </entry>
</feed>
