<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Strongly Typed - Home</title>
  <id>tag:www.joelpm.com,2008:mephisto/</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  <link href="http://www.joelpm.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://www.joelpm.com/" rel="alternate" type="text/html"/>
  <updated>2008-08-18T15:26:53Z</updated>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2008-08-18:114</id>
    <published>2008-08-18T15:23:00Z</published>
    <updated>2008-08-18T15:26:53Z</updated>
    <category term="Programming"/>
    <category term="programming"/>
    <category term="testing"/>
    <link href="http://www.joelpm.com/2008/8/18/the-utility-maintenance-ratio-of-tests" rel="alternate" type="text/html"/>
    <title>The Utility/Maintenance Ratio of Tests</title>
<content type="html">
            &lt;p&gt;
  When I think about writing or modifying software without some way of knowing if my changes have had unintended consequences it makes me nervous - nervous in the way a pilot might feel if he were asked to fly a plane with no instrument cluster. Yet, on the other hand, when I spend more time fixing/maintaining/debugging tests than doing feature development it makes me think there has got to be a better way - the instrument panel exists for the benefit of the pilot, not vice versa.
&lt;/p&gt;

&lt;p&gt;
  At work we run a pretty wide variety of tests against our software - JUnit, JsUnit, and Selenium tests that span everything from short method-level tests to large functional tests that start up the server with a mock environment. The short JUnit tests have never given me a problem and they run very quickly, so they have a high utility/maintenance ratio. The Selenium tests, on the other hand, take somewhere in the range of an hour to run, seem to be somewhat flaky, and are difficult to troubleshoot. Most of the problem is not with the Selenium part, per-se, but with the way the tests are run as part of an automated build and the fact that server start-up takes a long time. The overall result, though, is that the utility/maintenance ratio is very low. It's frustrating to spend a lot of time maintaining something that isn't part of the core product and isn't actively improving the end-user's experience - especially when it keeps me from working on things that would.
&lt;/p&gt;

&lt;p&gt;
  As a result, I've come to the conclusion that when the utility/maintenance ratio for a test suite drops below some value &lt;strong&gt;&lt;em&gt;N&lt;/em&gt;&lt;/strong&gt; you should consider it broken and take steps to fix it. I'm not sure what the specific fix is, but you should either decrease the amount of time you have to spend in maintenance or increase the utility of the tests dramatically. Since it's easier to measure time spent in maintenance I'd start there. The utility of a test suite tends to be binary - it either catches a problem or it doesn't.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2008-08-15:111</id>
    <published>2008-08-15T14:19:00Z</published>
    <updated>2008-08-15T15:00:56Z</updated>
    <category term="jobs"/>
    <category term="la"/>
    <link href="http://www.joelpm.com/2008/8/15/topspin-media" rel="alternate" type="text/html"/>
    <title>TopSpin Media</title>
<content type="html">
            &lt;p&gt;Occasionally I find out about interesting job opportunities in the Los Angeles area. I'm not currently looking but I thought I'd share these because if I wasn't working at Google I'd definitely be interested in these companies. I have no connection what-so-ever to these companies and no incentive to post these other than sharing something that looks like a good opportunity.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.topspinmedia.com/&quot;&gt;TopSpin Media&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;I can't remember how I found out about these guys, but they're working on a software solution designed to help artists connect with their fans in new and interesting ways (which should help artists to be more successful monetarily). This makes sense to me because as a fan I'm tired of having various third-parties inserted between the artist and myself - whether that be a marketing agency, a radio station, MTV, or someone else. Think Radiohead - they started a &lt;a href=&quot;http://www.radiohead.com/deadairspace/&quot;&gt;blog&lt;/a&gt;, released &quot;In Rainbows&quot; &lt;a href=&quot;http://www.inrainbows.com/&quot;&gt;as a download&lt;/a&gt; (with variable pricing), have posted &lt;a href=&quot;http://www.youtube.com/user/radiohead&quot;&gt;lots of videos&lt;/a&gt; on YouTube and, get this, released the &lt;a href=&quot;http://code.google.com/creative/radiohead/&quot;&gt;code and data&lt;/a&gt; for their video of &quot;House of Card.&quot; Radiohead has made it possible to connect with their creative process (and even &lt;a href=&quot;http://www.aniboom.com/radiohead/&quot;&gt;extend it&lt;/a&gt;) by using the internet, so when I read that TopSpin Media is working to &quot;help artists manage their catalogs, connect with fans, and generate demand for music&quot; it makes a lot of sense to me. I also like that TopSpin's mission is &quot;&lt;a href=&quot;http://topspinmedia.com/about/&quot;&gt;To provide artists the tools they need to build successful businesses&lt;/a&gt;.&quot; I paid $20 for Radiohead's &quot;In Rainbows&quot; when it came out, partly because I knew it was actually going to Radiohead and partly because I wanted to encourage that type of business model. If an artist has produced something of great worth they should reap the benefits directly, if they aren't producing quality[1] material then they should either go out of business or begin producing quality content.&lt;/p&gt;

&lt;p&gt;
In addition to liking what TopSpin is working on, they also promise &quot;the latest Mac hardware&quot; as a benefit. That alone makes me want to submit my resume. What I wouldn't give to have a shiny Mac Pro sitting on my desk, along with an MBP for working from home[2]. It looks like they're using Ruby and Java, which is also appealing to me. Then you've got the CEO and founders, who have done a &lt;a href=&quot;http://www.digidesign.com/&quot;&gt;thing&lt;/a&gt; or two (Yahoo! Music, Real Jukebox, LaunchCAST Radio) that was successful[3] in the past. 
&lt;/p&gt;

&lt;p&gt;
So, if you're into music, like Mac hardware, and are looking for a job go give &lt;a href=&quot;http://www.topspinmedia.com/&quot;&gt;TopSpin Media&lt;/a&gt; a look.
&lt;p&gt;
&lt;em&gt;[1]&lt;/em&gt; I realize there isn't necessarily a direct correlation between quality and popularity.&lt;br /&gt;
&lt;em&gt;[2]&lt;/em&gt; Google gives you your choice of MBP or Thinkpad when you start, in addition to a very nice Linux workstation.&lt;br /&gt;
&lt;em&gt;[3]&lt;/em&gt; Well, Yahoo! Music Unlimited isn't around anymore, but the idea  of a subscription music service has been shown successful.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2008-08-14:110</id>
    <published>2008-08-14T15:22:00Z</published>
    <updated>2008-08-14T18:03:48Z</updated>
    <category term="ibm"/>
    <category term="siggraph"/>
    <link href="http://www.joelpm.com/2008/8/14/siggraph-2008" rel="alternate" type="text/html"/>
    <title>SIGGraph 2008</title>
<content type="html">
            &lt;p&gt;
  Through work we got some free passes to the &lt;a href=&quot;http://www.siggraph.org/s2008/&quot;&gt;SIGGraph 2008&lt;/a&gt;
  exhibition hall, so yesterday morning we took a trip to the LA Convention Center and checked it out.
  There were lots of interesting displays and it looked to me like all of LA's mimes had been hired to
  put on black/white bodysuits with white/black dots on them to demo for all the companies selling motion
  capture technology. The demo that most impressed me, though was an
  &lt;a href=&quot;http://www-03.ibm.com/systems/bladecenter/hardware/servers/qs22/index.html&quot;&gt;IBM BladeCenter QS22&lt;/a&gt;
  doing real-time ray-tracing. I'm not sure why, but I dream about someday writing software that can wring
  every ounce of performance out of the hardware its running on.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2008-08-12:109</id>
    <published>2008-08-12T04:59:00Z</published>
    <updated>2008-08-12T05:50:27Z</updated>
    <category term="Blogging"/>
    <category term="git"/>
    <category term="mephisto"/>
    <link href="http://www.joelpm.com/2008/8/12/move-to-git-and-update-mephisto" rel="alternate" type="text/html"/>
    <title>Move to Git and Update Mephisto</title>
<content type="html">
            &lt;p&gt;
  Our internet connection on the vanpool isn't fast enough to do any actual work
  remotely (using NX) so I decided I'd use that time to update this site. While
  looking for info on the Mephisto's use of Liquid I noticed that there was a new
  version out, now available through Git rather than SVN. As a result I spent some
  time learning about Git and moving my repository for this site over to it. So
  far so good. Migrating from SVN was extremely easy thanks to
  &lt;a href=&quot;http://poocs.net/2008/4/19/mephisto-change-from-svn-to-git&quot;&gt;this write-up&lt;/a&gt;
  by Patrick Lenz.
&lt;/p&gt;

&lt;p&gt;
  After following the steps there you'll just need to update your deploy.rb
  to use git and your git respository - very straightforward. I'll
  post an article on using Git on Site5 (my shared host provider) soon.
&lt;/p&gt;

&lt;p&gt;
  I also finally finished the theme that I'd started last year. The colors
  are all borrowed from the Simpla theme since I'm an engineer and that's
  just not something I'm good at. The layout is my own, however. Writing a
  theme actually turned out to be easier than I thought.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2008-02-08:106</id>
    <published>2008-02-08T05:00:31Z</published>
    <updated>2008-02-08T05:39:24Z</updated>
    <category term="CSS"/>
    <category term="HTML"/>
    <category term="JavaScript"/>
    <link href="http://www.joelpm.com/2008/2/8/toggling-visibility-of-columns-in-a-table" rel="alternate" type="text/html"/>
    <title>Toggling Visibility of Columns in a Table</title>
<content type="html">
            &lt;p&gt;I've been working on some code that gets a bunch of data from the server (via XHR) and then builds a big table to display it all. The table is customizable and users can choose which columns they want to show/hide. The only problem is that whenever they show or hide a column we have to recreate the entire table (in Javascript with string concatenation) which is slow. Really slow. I've been thinking about ways around that and I've finally got one that works.&lt;/p&gt;

&lt;p&gt;In HTML we have TRs, which let us address individual table rows, but not TCs, so we can't easily identify a table column and modify it. To get around this we can artificially group the TD/TH elements that belong in a column using a CSS class. So, for example, our table could look like this:&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;ta&quot;&gt;&amp;lt;table&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;ta&quot;&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;ta&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;th&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Column 1&lt;span class=&quot;ta&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;th&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Column 2&lt;span class=&quot;ta&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;th&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Column 3&lt;span class=&quot;ta&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;th&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Column 4&lt;span class=&quot;ta&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;th&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Column 5&lt;span class=&quot;ta&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;th&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Column 6&lt;span class=&quot;ta&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;ta&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;ta&quot;&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;ta&quot;&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;ta&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;td&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Row1 Col1&lt;span class=&quot;ta&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;td&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Row1 Col2&lt;span class=&quot;ta&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;td&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Row1 Col3&lt;span class=&quot;ta&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;td&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Row1 Col4&lt;span class=&quot;ta&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;td&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Row1 Col5&lt;span class=&quot;ta&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;ta&quot;&gt;&amp;lt;td&lt;/span&gt; &lt;span class=&quot;an&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ta&quot;&gt;&amp;gt;&lt;/span&gt;Row1 Col6&lt;span class=&quot;ta&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;ta&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;ta&quot;&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;ta&quot;&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
 

&lt;p&gt;where the c1 through c6 classes are used to identify our columns. Now that we have a way of identifying a column we can use CSS to toggle it's visibility. We'll define a rule that says a TD or a TH that has the same class as the TABLE element should be hidden, like this:&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  table.c1 th.c1, table.c1 td.c1,&lt;tt&gt;
&lt;/tt&gt;  table.c2 th.c2, table.c2 td.c2,&lt;tt&gt;
&lt;/tt&gt;  table.c3 th.c3, table.c3 td.c3,&lt;tt&gt;
&lt;/tt&gt;  table.c4 th.c4, table.c4 td.c4,&lt;tt&gt;
&lt;/tt&gt;  table.c5 th.c5, table.c5 td.c5,&lt;tt&gt;
&lt;/tt&gt;  table.c6 th.c6, table.c6 td.c6 {&lt;tt&gt;
&lt;/tt&gt;    display: none;&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;/style&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;When the table doesn't have any of the classes applied the TD or TH elements get the default display value and are visible. However, if we want to hide column three all we have to do is add the &quot;c3&quot; class to the TABLE element and column three will be hidden. While it might seem a little unintuitive that we &lt;em&gt;add&lt;/em&gt; the column class to our table to &lt;em&gt;remove&lt;/em&gt; the column, we do that because then we can use 'display: none' instead of defining what the visible display state should be. And why does that matter? Because there are &lt;a href=&quot;http://www.w3schools.com/css/pr_class_display.asp&quot;&gt;sixteen visible display states&lt;/a&gt; and only one hidden state and this way we can let the browser figure out what the right visible display states for TD/TH elements are.&lt;/p&gt;

&lt;p&gt;To see this concept in action you can take a look at &lt;a href=&quot;http://www.joelpm.com/assets/2008/2/8/HideableColumns.html&quot;&gt;this simple page&lt;/a&gt; I threw together.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2008-01-20:104</id>
    <published>2008-01-20T04:40:10Z</published>
    <updated>2008-01-20T04:42:44Z</updated>
    <category term="OS X"/>
    <link href="http://www.joelpm.com/2008/1/20/ipod-iphone-lifemachine" rel="alternate" type="text/html"/>
    <title>iPod/iPhone LifeMachine</title>
<content type="html">
            &lt;p&gt;My wife and I went for a hike the other day. Before we left I grabbed my camera, my phone, and my iPod. It occurred to me later that I take those three devices with me just about everywhere I go. I'm really looking forward to the day when they converge into one device that performs all three functions well. The iPhone is getting close, but it doesn't have the capacity of my 30GB 5G iPod or the resolution of my Canon SD 450. On the other hand it does have a bigger screen than my camera, iPod, or phone and strongly out performs my RAZR in phone functionality. I'd guess that the second or third generation iPhone will fulfill all three of those roles satisfactorily.&lt;/p&gt;

&lt;p&gt;So far I'm not asking for anything radical. However, what I think would make a truly &lt;strong&gt;brilliant&lt;/strong&gt; device would be if Apple stuck a 500GB hard drive in the iPhone and made it work as a backup location for TimeMachine. Then, go one step farther and make the data stored in the TimeMachine backup accessible/viewable - at least the important bits - through the iPod/iPhone interface. Think about it, my iPod already contains a majority of my music, pictures, and movies (which is the bulk of the data on my laptop) and it's accessible - I can look at pics or play music and movies. Why not go one step further and back-up all my data to my iPod and make all the important bits accessible/viewable?&lt;/p&gt;

&lt;p&gt;Every time you connect your iPod to your computer you're essentially backing up all your digital entertainment. Then when you plug in your USB/FW drive for use with TimeMachine the same thing is happening, except that it's a different drive and you can't access any of the data stored on the drive without connecting to an OS X machine. I think Apple should modify the iPod/iPhone OS so that it can read TimeMachine backups, stick a 500GB HD in the device, and call it the iPod/iPhone LifeMachine. So maybe the name's not real hot, but I would pay serious coinage for this device (whatever it got called) if Apple released one.&lt;/p&gt;

&lt;p&gt;So please, Apple, let me do away with my camera, phone, iPod, and external TimeMachine drive and replace it with an iPod LifeMachine.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2008-01-07:103</id>
    <published>2008-01-07T23:12:57Z</published>
    <updated>2008-01-07T23:12:57Z</updated>
    <category term="Programming"/>
    <link href="http://www.joelpm.com/2008/1/7/goal-do-something-significant" rel="alternate" type="text/html"/>
    <title>Goal: Do Something Significant</title>
<content type="html">
            &lt;p&gt;
	I'm not big on New Year's resolutions. First, it seems to me like people who get one chance a
	year to make a resolution are at a disadvantage compared to those who can introspect at any
	point in the year and decide that &quot;Starting now I want to ________.&quot; Secondly, a resolution
	seems like a thing that is more often broken than maintained, and once broken left by the
	wayside until the next opportunity to make (and possibly break) it again. For these reasons I
	prefer goals. A goal can be set at any time and you never 'break' your goal. You may not have
	achieved it yet, but that doesn't imply that you've stopped trying or somehow missed your
	opportunity to achieve it.
&lt;/p&gt;
&lt;p&gt;
	While thinking about the past year I realized that I learned several new programming languages
	but didn't really accomplish anything significant in any of them. I learned Ruby (and Rails),
	Python for work, and spent some time looking at Scala (which I really like), and have recently
	started learning Objective-C and Cocoa. My goal, starting now, is to stick with a language until
	I've accomplished something significant in the language. I'm not sure what I mean by significant
	yet - possibly something that can be used by others - but when I accomplish it I'll know.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-11-16:102</id>
    <published>2007-11-16T05:52:17Z</published>
    <updated>2007-11-16T05:52:17Z</updated>
    <category term="Xanga"/>
    <link href="http://www.joelpm.com/2007/11/16/monsur-joins-google" rel="alternate" type="text/html"/>
    <title>Monsur Joins Google</title>
<content type="html">
            &lt;img src=&quot;http://www.joelpm.com/assets/2007/11/16/server_move1_small.jpg&quot; /&gt;
&lt;p&gt;I met &lt;a href=&quot;http://www.xanga.com/monsur&quot;&gt;Monsur&lt;/a&gt; in April of 2005. I'd flown to New York on a Thursday night for an interview with &lt;a href=&quot;http://www.xanga.com&quot;&gt;Xanga&lt;/a&gt;. He and &lt;a href=&quot;http://www.xanga.com/jon&quot;&gt;Jon&lt;/a&gt; met me at the hotel and took me to Times Square Brewery for a late dinner. After forty-eight hours of coding, eating, drinking, and socializing with the team I received a job offer and that was the beginning of my association with Monsur (as well as the rest of the great folks at Xanga).&lt;/p&gt;

&lt;p&gt;Over the course of the next year I got to work closely with Monsur on various projects, be there when he got married, see Ted Leo and the Pharmacists, go on recruiting trips, attend PDC, and move over a hundred racked servers in the back of a U-Haul (see the pics). I've no doubt that life would have continued in much the same vein except that I met an amazing girl in California and decided to move across the country and marry her, which led to the close of the Xanga chapter in my life.&lt;/p&gt;

&lt;img src=&quot;http://www.joelpm.com/assets/2007/11/16/server_move2_small.jpg&quot; /&gt;
&lt;p&gt;I've been blessed thus far in my life that I've never left a job because I didn't like the job - IBM was a great place to work, I have very fond memories (and a groomsman) from my time at Xanga, and Latham &amp; Watkins was very good to me. In addition I can honestly say that I'd welcome to opportunity to work again with many of my past co-workers, which is why I'm really excited that Monsur accepted a job at Google. As one of the first programmers (perhaps &lt;em&gt;the&lt;/em&gt; first) at Xanga I never expected Monsur to leave, so when I heard he was interviewing with Google I was shocked. However, I can attest to the fact that sometimes you have to leave something good behind because a new opportunity has arisen, and I'm glad that this new opportunity for Monsur is here at Google.&lt;/p&gt;

&lt;p&gt;Congrats Monsur and welcome to Google! It's unlikely that we'll get called upon to move racks of servers here :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-11-07:101</id>
    <published>2007-11-07T07:00:15Z</published>
    <updated>2007-11-07T07:00:48Z</updated>
    <category term="Programming"/>
    <category term="Ruby"/>
    <link href="http://www.joelpm.com/2007/11/7/reading-rhapsody-s-rss-with-ruby" rel="alternate" type="text/html"/>
    <title>Reading Rhapsody's RSS with Ruby</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://www.rhapsody.com/&quot;&gt;Rhapsody&lt;/a&gt;, a subscription music service I've used for the last couple years, makes a lot of their data available through RSS feeds and XML. For a project I'm working on I wanted to parse one of their RSS feeds with Ruby and I thought I'd share how I did it.&lt;/p&gt;

&lt;p&gt;The Rhapsody feeds are RSS 2.0 but also include Rhapsody specific elements in the 'rhap' namespace, so it was necessary to use a parser that could be extended to parse these elements. Ruby includes a library for parsing RSS but after reading the source I wasn't sure how to extend it. Fortunately, some searching turned up the &lt;a href=&quot;http://syndication.rubyforge.org/&quot;&gt;Syndication&lt;/a&gt; library which the author designed to be easily extended. After doing a 'gem install syndication' you're all set to begin coding.&lt;/p&gt;

&lt;p&gt;The Syndication parser works by defining objects that map (roughly) to elements in the RSS document. When the parser is parsing an element it maps element attributes to object attributes with namespace (if any) prepended to the object attribute with an underscore. For example, the attribute rhap:rcid would become rhap_rcid and if an attr_accessor named rhap_rcid existed on the object it would get set to the value of the rhap:rcid attribute. I wanted to extend the Syndication::RSS:Item class so I started out by defining a module called Syndication::Rhapsody::Item that had all the properties I was interested in. Then, with that defined, it was simply a matter of including this module in the Syndication::RSS:Item class:&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;syndication/rss&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Syndication&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Rhapsody&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Item&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_rcid&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_artist&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_artist_rcid&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_album&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_album_rcid&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_album_art&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_album_release_date&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_album_original_release_date&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      attr_accessor &lt;span class=&quot;sy&quot;&gt;:rhap_album_type&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;c&quot;&gt;# Need to override the tag2method defined in class Container because it&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;c&quot;&gt;# doesn't deal with tags with dashes in them. Ruby can't handle method&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;c&quot;&gt;# names with dashes so we switch to underscores.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;tag2method&lt;/span&gt;(tag)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; tag.downcase.gsub(&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;[:-]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;) + &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;RSS&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Item&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        include &lt;span class=&quot;co&quot;&gt;Rhapsody&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Item&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;You'll notice that I also ended up overriding the definition of the tag2method method. This is because Ruby doesn't allow variable names with hyphens (quite sensibly) so the elements in the 'rhap' namespace that had a hyphen in them were getting ignored. To fix that I simply had tag2method substitute an underscore for a hyphen.&lt;/p&gt;

&lt;p&gt;With the Syndication::RSS::Item modified it's now simply a matter of creating the parser and reading the feed:&lt;/p&gt;

&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;rss/2.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;open-uri&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;syndication/rhapsody&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;RhapsodyReader&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;initialize&lt;/span&gt;(url = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://feeds.rhapsody.com/new-releases.rss&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@url&lt;/span&gt; = url&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;read&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    parser = &lt;span class=&quot;co&quot;&gt;Syndication&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;RSS&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Parser&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@feed&lt;/span&gt; = &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    open(&lt;span class=&quot;iv&quot;&gt;@url&lt;/span&gt;) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |s|&lt;tt&gt;
&lt;/tt&gt;      content = s.read&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@feed&lt;/span&gt; = parser.parse content&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@feed&lt;/span&gt;.items.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |item|&lt;tt&gt;
&lt;/tt&gt;      puts &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Got rcid '&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;item.rcid&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;For more information on the Rhapsody web-service you can go here: &lt;a href=&quot;http://webservices.rhapsody.com/&quot;&gt;http://webservices.rhapsody.com/&lt;/a&gt;. Like I mentioned above, Rhapsody also makes some of their data available as non-RSS XML and I'll write about using REXML to parse it in the future.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-11-04:100</id>
    <published>2007-11-04T06:01:00Z</published>
    <updated>2007-11-04T06:05:26Z</updated>
    <category term="blogging"/>
    <category term="mephisto"/>
    <category term="rails"/>
    <category term="software"/>
    <link href="http://www.joelpm.com/2007/11/4/living-the-dream" rel="alternate" type="text/html"/>
    <title>Living the Dream</title>
<content type="html">
            &lt;p&gt;
	When &lt;a href=&quot;http://www.red-sweater.com/marsedit/&quot;&gt;MarsEdit 2&lt;/a&gt; was released I
	decided I wanted to try blogging using a client app instead of
	&lt;a href=&quot;http://www.mephistoblog.com/&quot;&gt;Mephisto&lt;/a&gt;'s web interface. However, when
	I tried connecting to Mephisto using XML-RPC I kept getting errors. This eventually
	led me to upgrade to the edge version of Mephisto which requires edge rails and while
	I was at it I also switched to Capistrano 2.1.
&lt;/p&gt;
&lt;p&gt;
	Because I'm nowhere near being a Ruby or Rails guru the whole process took me longer
	than it should have. All the effort was worth it, though, when I was able to make
	changes on my dev machine and then type 'cap deploy' and have it magically appear on
	the server hosting this blog. That is truly living the dream.
&lt;/p&gt;
&lt;p&gt;
	My goal is to write more frequently and chronicle some of the things I'm tinkering
	with in my spare time. I also plan on writing up my thoughts on software that I try
	out, like MarsEdit 2, for instance.
&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-11-03:99</id>
    <published>2007-11-03T05:07:23Z</published>
    <updated>2007-11-03T05:29:24Z</updated>
    <category term="OS X"/>
    <link href="http://www.joelpm.com/2007/11/3/marsedit" rel="alternate" type="text/html"/>
    <title>MarsEdit</title>
<content type="html">
            &lt;h1&gt;MarsEdit!&lt;/h1&gt;
&lt;p&gt;This is a test to see how the whole MarsEdit thing works.&lt;/p&gt;
&lt;p&gt;It was a real hassle getting xmlrpc working.&lt;/p&gt;
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;foo&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;init&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    puts &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Got inited&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Code highlighting seems to be a pain in the rear, with no definitive answer on how it's supposed to be done.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-07-17:44</id>
    <published>2007-07-17T07:05:00Z</published>
    <updated>2007-07-17T07:09:50Z</updated>
    <category term="family"/>
    <category term="google"/>
    <link href="http://www.joelpm.com/2007/7/17/dad-joins-google" rel="alternate" type="text/html"/>
    <title>Dad Joins Google</title>
<content type="html">
            &lt;img src=&quot;http://www.joelpm.com/assets/2007/7/17/dad.jpg&quot; /&gt;
&lt;p&gt;Back in February I convinced my dad to let me refer him for the position of &lt;a href=&quot;http://www.google.com/support/jobs/bin/answer.py?answer=57581&quot;&gt;Senior Ads Quality Statistician&lt;/a&gt; at Google. I knew he was an excellent candidate and would be perfect for the position but I didn't know if anyone would be able to convince Dr. and Mrs. Meyer to pick up and leave the family farm in Illinois for a stint in Souther California. Not surprisingly, Google made an offer. Vanderbilt did too. Then his current place of employment made a ridiculously large counter-offer. After much deliberation he's accepted the Google offer.&lt;/p&gt;

&lt;p&gt;Congratulations dad, Google is lucky to get you! It'll be great to work together again as well as having you and mom live a few thousand miles closer :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-07-13:43</id>
    <published>2007-07-13T15:29:00Z</published>
    <updated>2007-07-13T17:19:59Z</updated>
    <category term="bluetooth"/>
    <category term="technology"/>
    <link href="http://www.joelpm.com/2007/7/13/bluetooth-finally" rel="alternate" type="text/html"/>
    <title>Bluetooth, finally</title>
<content type="html">
            &lt;p&gt;During my senior year in college (2001-02) I took CS292 (since renumbered to &lt;a href=&quot;http://www.cs.uiuc.edu/undergraduate/courses.php?course=cs492&quot;&gt;CS492&lt;/a&gt;), a senior design project class. While our &lt;a href=&quot;http://slappy.cs.uiuc.edu/fall01/team6/&quot;&gt;project&lt;/a&gt; was not the most exciting (we were evaluating which programming languages were well suited for COM development) &lt;a href=&quot;http://slappy.cs.uiuc.edu/fall01/team5/project.html&quot;&gt;another group&lt;/a&gt; worked on a program for Motorola that would help them debug their Bluetooth implementation. As we were all required to present on our projects, their presentations were my introduction to the Bluetooth communications protocol and all the potential it held.&lt;/p&gt;

&lt;p&gt;That was five years ago and my visions of a connected utopia have been slow to materialize. However, several things have happened recently that persuade me there is still hope for the future, the most convincing of which occurred last night when I was out with my mother and father-in-law. As we were walking back to their Prius my father-in-law got a call on his cell phone. It was his brother, calling to finalize some details about the birthday dinner for their mother next week. When we got in the car and my mother-in-law turned it on it was suddenly filled with the sound of Uncle Charlie's voice. Why? The Prius had detected that one of the phones it was paired with was engaged in a call and seamlessly switched it over to the car's audio system. At that point all three of us were able to participate in the conversation - the audio quality was good and we didn't have to talk louder than normal to be heard.&lt;/p&gt;

&lt;p&gt;In a similar vein, a couple weeks ago I ordered Aliph &lt;a href=&quot;http://www.jawbone.com/&quot;&gt;Jawbone&lt;/a&gt;s for my wife and myself so we could talk to family and friends while we're taking care of stuff around the house. Pairing the Jawbone with the phones (Moto Razr and Moto Krzr) is straightforward and the voice quality is good. I'm also impressed by the fact that adjusting the volume on my phone will also adjust the volume in the Jawbone when it's in use. In fact, when I'm using the headset I don't have to hit any buttons on it at all - it acts just like an extension of the cell phone, which is exactly the way I want it to be. When I use bluetooth to pair two devices I don't want to have to manage both devices, I want to manage one and have the  other act like an extension of it.&lt;/p&gt;

&lt;p&gt;The next several items are all computer related. First, my wife uses her Moto Krzr as an EVDO modem with her MacBook via Bluetooth and has been doing so for the last half-year. While the speed is less than blistering it provides solid performance and lets her connect anywhere she's got a digital signal. I use Bluetooth to sync my contacts between my phone and my MacBook Pro. And finally, earlier this year I was able to use my phone as a modem (paired with my MacBook Pro via Bluetooth) to send a fax from Mail.app.&lt;/p&gt;

&lt;p&gt;Even though it's taken a while (at least here in the U.S.) I feel like we're finally reaching a point where Bluetooth is really useful. I have to commend Apple for doing such a good job supporting Bluetooth in their operating system and chastise Verizon for their habit of crippling and disabling various Bluetooth profiles in order to force customers to use their (costly) services instead.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-07-11:42</id>
    <published>2007-07-11T17:48:00Z</published>
    <updated>2007-07-11T17:53:33Z</updated>
    <category term="google"/>
    <category term="ibm"/>
    <category term="monitors"/>
    <category term="saic"/>
    <category term="tellabs"/>
    <category term="xanga"/>
    <link href="http://www.joelpm.com/2007/7/11/monitors" rel="alternate" type="text/html"/>
    <title>Monitors</title>
<content type="html">
            &lt;p&gt;My first internship was with a company called &lt;a href=&quot;http://www.tellabs.com/&quot;&gt;Tellabs&lt;/a&gt; that made telecom products - large, powerful boxes that did telephone switching. These big huge boxes generated big huge log files and my task was to write a Perl program that made it easier for engineers to search through and get what they needed from the log files. My computer was an aging Sun something-or-other.&lt;/p&gt;

&lt;p&gt;My second internship was with &lt;a href=&quot;http://www.saic.com/&quot;&gt;SAIC&lt;/a&gt; where I spent the first part of my summer writing code to parse various binary file types and the second part implementing terrain rendering algorithms in C++/OpenGL. My computer was again an aging relic with FPS measurements usually less than one (no textures, just tri-strips and simple shading): an SGI Indigo.&lt;/p&gt;

&lt;p&gt;When I started at &lt;a href=&quot;http://www.ibm.com/&quot;&gt;IBM&lt;/a&gt; I was given an older T21 laptop and a decent workstation. By the time I left I had a top of the line T42, a top of the line T41, and a very powerful workstation with a pro-grade graphics card that was unfortunately never utilized. I also had a 19&quot; CRT monitor.&lt;/p&gt;

&lt;p&gt;After my first two internships my experience at IBM was a welcome change - finally a place that provided its engineers with really good equipment. From them I learned the value of having the best tools available and three years later when I was interviewing at &lt;a href=&quot;http://www.xanga.com/&quot;&gt;Xanga&lt;/a&gt; one of the things I evaluated them on was the type of equipment their developers had. As it turned out, they gave their devs very good equipment, which came in handy when we played Counter-Strike or Battlefield 2 in the evenings, as well as when programming, of course. It was at Xanga that I was first able to experience a dual-monitor setup. I started with two 19&quot; monitors and graduated to a 24&quot; and a 20&quot; a little later.&lt;/p&gt;

&lt;p&gt;While I was at Xanga experiencing my new found screen real-estate wealth I couldn't help but wonder what it would be like to have dual 24&quot; monitors, a curiosity that was satisfied when I started at &lt;a href=&quot;http://www.google.com/&quot;&gt;Google&lt;/a&gt;, where dual 24&quot; monitors was the default for engineers. The amount of screen real-estate you get with dual 24&quot; monitors is amazing. I can have Eclipse maximized in one screen and have a large browser window, a terminal, and a text editor on the other screen, like this:&lt;/p&gt;
&lt;img src=&quot;http://www.joelpm.com/assets/2007/7/11/dual24inch.sized.jpg&quot; /&gt;
&lt;p&gt;What I hadn't expected, though, was the amount of head turning it would take to shift my gaze from one monitor to the next. And, believe it or not, even with &lt;a href=&quot;http://www.eclipse.org/&quot;&gt;Eclipse&lt;/a&gt; maximized on one monitor things still felt cramped when I had two code panes open side-by-side (my default mode of operating). So when the opportunity arose to trade in my 24&quot;s for a 30&quot; monitor I jumped at it. After using the 30&quot; for a couple weeks I think I made the right decision. Eclipse maximized on a 30&quot; monitor is a beautiful thing. I can see two full code panes, stack the Package Explorer view on top of the Outline view and both are still usable. The benefit is also apparent in the Debug perspective when there are even more views, all with useful information, visible at the same time. I can see the call stack, the variables currently in scope, the console, and the editor view is actually usable when you're stepping through code:&lt;/p&gt;
&lt;img src=&quot;http://www.joelpm.com/assets/2007/7/11/30inch.sized.jpg&quot; /&gt;
&lt;p&gt;Another advantage of the 30&quot; monitor is that I don't have to move my head as much, especially to look at something on my laptop, which I use for email and messaging. A drawback is that I can't see Eclipse and Firefox at the same time so I end up alt-tabbing between them, but it's not as much of a drawback as I had thought it might be. For reference, that's a 15&quot; MacBook Pro on the left and a Lenovo X60 on the right.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.joelpm.com/">
    <author>
      <name>Joel</name>
    </author>
    <id>tag:www.joelpm.com,2007-06-21:39</id>
    <published>2007-06-21T21:11:00Z</published>
    <updated>2007-06-21T21:18:43Z</updated>
    <category term="json"/>
    <category term="python"/>
    <link href="http://www.joelpm.com/2007/6/21/" rel="alternate" type="text/html"/>
    <title>\/\*\* .* \*/</title>
<content type="html">
            &lt;p&gt;That may look like some weird form of ASCII art, but it's really a regular expression that will find all short-from Javadoc comments. You can try it out yourself &lt;a href=&quot;http://www.google.com/codesearch?as_q=%5C%2F%5C*%5C*+.*+%5C*%5C%2F&amp;amp;btnG=Search+Code&amp;amp;hl=en&amp;amp;as_lang=&amp;amp;as_license_restrict=i&amp;amp;as_license=&amp;amp;as_package=&amp;amp;as_filename=%5C.java%24&amp;amp;as_case=&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As far as my ToDo list goes, I've written Java code that will serialize an object to JSON and the deserialization will get implemented when I get a few hours to bang away on it. Once that's working I'd like to make it available somewhere. I've also learned enough Python to do what I need to do. I have friends (well, at least one) who really like Python but my impression of it so far is that it's basically like Javascript for the non-browser world. I'm sure that if I spent more time with the language I'd feel differently, but for now I miss my semicolons and brackets and type declarations.&lt;/p&gt;
          </content>  </entry>
</feed>
