<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Shhhaw - Alexander Shaw&apos;s Home on the Web</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/" />
    <link rel="self" type="application/atom+xml" href="http://www.shhhaw.com/feed.xml" />
    <id>tag:www.shhhaw.com,2009-08-30://1</id>
    <updated>2013-03-15T00:54:03Z</updated>
    <subtitle>Alexander Shaw&apos;s Home on the Web</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.261</generator>

<entry>
    <title>Outsider CAR: Quick Thoughts on Malofiej 21 Day 1</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2013/03/outsider-car-quick-thoughts-on-malofiej-21-day-1.php" />
    <id>tag:www.shhhaw.com,2013://1.68</id>

    <published>2013-03-14T19:31:10Z</published>
    <updated>2013-03-15T00:54:03Z</updated>

    <summary><![CDATA[While the big graphics teams presented at the Malofiej Infographic Summit in Pamplona, Spain, there were also examples of artists and designers applying their own brand of CAR. Read more at the ProPublica Nerd Blog &raquo;...]]></summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p><img src="http://www.propublica.org/images/ngen/gypsy_image_medium/cache/posavec-map-140-70x70.jpg" style="float:left;margin-right:10px;margin-bottom:10px;">While the big graphics teams presented at the Malofiej Infographic Summit in Pamplona, Spain, there were also examples of artists and designers applying their own brand of CAR. <em> <a href="http://www.propublica.org/nerds/item/outsider-car-quick-thoughts-on-malofiej-21-day-1">Read more at the ProPublica Nerd Blog &raquo;</a></em></p>

<div style="clear:both;"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>Where You Can See Me Blather at NICAR 13</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2013/02/al-at-nicar-13.php" />
    <id>tag:www.shhhaw.com,2013://1.67</id>

    <published>2013-02-27T19:48:31Z</published>
    <updated>2013-03-02T20:17:09Z</updated>

    <summary>I&#8217;ll be speaking at a number of sessions at this year&#8217;s NICAR conference in Louisville. If you liked last year&#8217;s Scraping with Node in two minutes (plus questions) lightning talk, I&#8217;ll be reprising it this year for a whole hour,...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>I&#8217;ll be speaking at a number of sessions at this year&#8217;s NICAR conference in Louisville. If you liked last year&#8217;s Scraping with Node in two minutes (plus questions) lightning talk, I&#8217;ll be reprising it this year for a whole hour, among other topics! Watch this space for links to slides, too.</p>

<p><img class="gutter" src="http://farm8.staticflickr.com/7205/6932532833_f612c3ba45.jpg" style="width:250px;margin-right:15px;margin-bottom:15px;"></p>

<h3>Friday, March 1</h3>

<ul>
<li>10:00 a.m. Intro to Ruby (<a href="http://shaw.al.s3.amazonaws.com/nicar13/nicar-2013-ruby.html">slides</a>)</li>
<li>4:00 p.m. Lightning Talk: Casino Driven Design (<a href="http://shaw.al.s3.amazonaws.com/nicar13/nicar-2013-casino.html">slides</a>)</li>
</ul>

<h3>Saturday, March 2</h3>

<ul>
<li>11 a.m. Web Scraping with Node (<a href="http://shaw.al.s3.amazonaws.com/nicar13/nicar-2013-node.html">slides</a>)</li>
<li>2 p.m. Infect the CMS <em>(with Jake Harris and Heather Billings)</em> (<a href="https://github.com/harrisj/infect-the-cms">slides</a>)</li>
</ul>

<p>(Photo by Ben Welsh)</p>

<div style="clear:both"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>Building Micro Web Apps in Ruby at NYU Studio 20</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2011/03/building-micro-web-apps-in-ruby-at-nyu-studio-20.php" />
    <id>tag:www.shhhaw.com,2011://1.66</id>

    <published>2011-03-28T14:05:54Z</published>
    <updated>2011-03-28T14:19:04Z</updated>

    <summary>My colleague Dan Nguyen and I led a four hour workshop at the NYU J School&#8217;s Studio 20 program yesterday starting with beginning programming with Ruby, leading up to building simple web apps with Sinatra. Here are the slides for...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>My colleague <a href="http://twitter.com/dancow">Dan Nguyen</a> and I led a four hour workshop at the NYU J School&#8217;s <a href="http://journalism.nyu.edu/graduate/courses-of-study/studio-20/">Studio 20</a> program yesterday starting with beginning programming with Ruby, leading up to building simple web apps with <a href="http://www.sinatrarb.com/">Sinatra</a>. Here are the slides for the latter portion, largely based on my similar <a href="http://www.alistapart.com/articles/rapid-prototyping-with-sinatra/">article</a> in A List Apart:</p>

<p><object id="__sse7415906" width="425" height="355"> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=sinatra-deck-110328090430-phpapp01&amp;stripped_title=simple-web-apps-with-sinatra&amp;userName=a_l" /> <param name="allowFullScreen" value="true"/> <param name="allowScriptAccess" value="always"/> <embed name="__sse7415906" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=sinatra-deck-110328090430-phpapp01&amp;stripped_title=simple-web-apps-with-sinatra&amp;userName=a_l" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed> </object></p>
]]>
        

    </content>
</entry>

<entry>
    <title>Learning to `chmod` the News: My Talk at Columbia J-School</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2011/02/learning-to-chmod-the-news-my-talk-at-columbia-j-school.php" />
    <id>tag:www.shhhaw.com,2011://1.65</id>

    <published>2011-02-26T18:20:00Z</published>
    <updated>2011-02-26T21:39:30Z</updated>

    <summary><![CDATA[My friend Tyson invited me to speak to his Digital News Design class at Columbia Journalism School yesterday. Here are the slides: Links mentioned in the talk: ProPublica Tools &amp; Data TPM PollTracker FireDogLake - Prop 19 Polls: Look at...]]></summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="Design" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="me" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>My friend <a href="http://tysonevans.com">Tyson</a> invited me to speak to his Digital News Design class at Columbia Journalism School yesterday. Here are the slides:</p>

<p><object id="__sse7071059" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=columbia-preso-110226120756-phpapp02&amp;stripped_title=learning-to-chmod-the-news&amp;userName=a_l" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse7071059" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=columbia-preso-110226120756-phpapp02&amp;stripped_title=learning-to-chmod-the-news&amp;userName=a_l" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></p>

<p>Links mentioned in the talk:</p>

<ul>
<li><a href="http://www.propublica.org/tools/">ProPublica Tools &amp; Data</a></li>
<li><a href="http://polltracker.talkingpointsmemo.com">TPM PollTracker</a></li>
<li><a href="http://justsaynow.firedoglake.com/2010/10/21/prop-19-polls-look-at-the-trends/">FireDogLake - Prop 19 Polls: Look at the Trends</a></li>
<li><a href="http://andrewsullivan.theatlantic.com/the_daily_dish/2010/10/the-prop-19-polls-tighten.html">Andrew Sullivan - The Prop 19 Polls Tighten</a></li>
<li><a href="http://projects.propublica.org/docdollars">ProPublica - Dollars for Docs</a></li>
<li><a href="http://blogs.villagevoice.com/runninscared/2010/10/my_doctor_took.php">Village Voice - My Doctor Took Money from a Drug Company, and Then Prescribed Me Their Drugs</a></li>
<li><a href="http://www.swiss-miss.com/2009/06/creativemornings-with-khoi-vinh.html">Khoi Vinh at CreativeMornings</a></li>
<li><a href="http://www.shhhaw.com/2009/05/on-redesigning-the-front-page-of-talking-points-memo.php">Al Shaw - On Redesigning the Front Page of Talking Points Memo</a></li>
<li><a href="http://powazek.com/posts/2090">Derek Powazek - Spammers, Evildoers, and Opportunists</a></li>
<li><a href="http://37signals.com/svn/posts/2582-how-do-i-learn-to-program">David Heinemeier Hansson - How do I learn to program?</a></li>
<li><a href="http://election2010.talkingpointsmemo.com">TPM ElectionCenter 2010</a></li>
<li><a href="http://projects.propublica.org/dialysis">ProPublica - Dialysis Facility Tracker</a></li>
<li><a href="http://projects.propublica.org/forensics/">ProPublica - Autopsies in the U.S.A.</a></li>
</ul>
]]>
        

    </content>
</entry>

<entry>
    <title>I Wrote an Intro to Sinatra for A List Apart</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2011/02/i-wrote-an-intro-to-sinatra-for-a-list-apart.php" />
    <id>tag:www.shhhaw.com,2011://1.64</id>

    <published>2011-02-22T16:55:18Z</published>
    <updated>2011-02-22T16:57:17Z</updated>

    <summary>I wrote a Sinatra explainer from a rapid prototyping standpoint in A List Apart. If you make it to the end, you might have a small but working Twitter app that looks a lot like DoesFollow. If you&#8217;re a web...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="ALA" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Sinatra" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>I wrote a Sinatra explainer from a rapid prototyping standpoint in A List Apart. If you make it to the end, you might have a small but working Twitter app that looks a lot like <a href="http://doesfollow.com">DoesFollow</a>.</p>

<blockquote>
  <p>If you&#8217;re a web designer or developer, you&#8217;re well acquainted with prototyping. From raw wireframing to creating interfaces in Photoshop, designers map out how sites will work before they create them. Over the past few years, the protoyping process has changed significantly. With browser makers generally agreeing on web standards and the rise of tools such as Firebug and WebKit&#8217;s web inspector, we can sometimes skip Photoshop and go straight to the browser. Plus, JavaScript frameworks like jQuery let us play with browser events with only a few lines of code. But what if we need to do even more? As websites increasingly become web apps, we now need to prototype backend functionality, too. Learn how Sinatra, a so-called &#8220;micro&#8221; web framework, helps you create real (albeit simple) web apps extremely fast, letting you prototype flows and behavior you may want to integrate into a final product.</p>
</blockquote>

<p>Read the <a href="http://www.alistapart.com/articles/rapid-prototyping-with-sinatra/">whole thing at ALA</a> and grab the <a href="https://github.com/ashaw/ALA-Sample-Sinatra-App">code for the sample app</a>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>TwitterBnter: A Little App to Post Twitter Conversations on Bnter</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2011/02/twitterbnter-a-little-app-to-post-twitter-conversations-on-bnter.php" />
    <id>tag:www.shhhaw.com,2011://1.63</id>

    <published>2011-02-10T19:13:36Z</published>
    <updated>2011-02-10T19:13:57Z</updated>

    <summary> Bnter is a site that lets you post conversations. Weirdly, they don&#8217;t allow you to natively import Twitter conversations without retyping them. I wrote a fun little app called TwitterBnter that pulls conversations from tweet IDs or URLs and...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="Sinatra" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p><img src="http://bnter.com/convo/11641.png" alt="twitterbnter" title="" /></p>

<p><a href="http://bnter.com">Bnter</a> is a site that lets you post conversations. Weirdly, they don&#8217;t allow you to natively import Twitter conversations without retyping them. I wrote a fun little app called <a href="http://twitterbnter.shhhaw.com">TwitterBnter</a> that pulls conversations from tweet IDs or URLs and automatically posts them to Bnter (via their cool OAuth <a href="http://bnter.com/api">API</a>. Note, Bnter only allows three max exchanges per conversation right now, so TwitterBnter will drill back as far as it can in the convo from the tweet you submit (use the most recent for best results), take the first three exchanges and reverse it, so the first one goes on top in the Bnter post.</p>

<p>Try it out here: <a href="http://twitterbnter.shhhaw.com">http://twitterbnter.shhhaw.com</a>. Ruby source code <a href="https://github.com/ashaw/twitterbnter">on github</a>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Introducing Trippy: An App to Give You *Just* Enough to Read on Your Commute </title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/12/introducing-trippy-an-app-to-give-you-just-enough-to-read-on-your-commute.php" />
    <id>tag:www.shhhaw.com,2010://1.62</id>

    <published>2010-12-06T04:08:40Z</published>
    <updated>2010-12-11T16:55:24Z</updated>

    <summary>I had a couple ideas going into the TimesOpen hack day. One came out of meeting the dude behind @longreads, a Twitter account and blog aggregating long form journalism, at a Hacks/Hackers event. The Longreads blog has a unique feature:...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>I had a couple ideas going into the <a href="http://www.nytimes.com/marketing/timesopen/hackday.html">TimesOpen hack day</a>. One came out of meeting the dude behind @<a href="http://twitter.com/longreads">longreads</a>, a Twitter account and blog aggregating long form journalism, at a Hacks/Hackers event.</p>

<p><img class="gutter" src="http://www.shhhaw.com/images/trippy-long-sg.png" alt="TRIPPY"></p>

<p>The Longreads blog has a unique feature: it tells you how long it will take you to read each article (I figured out that it takes the article&#8217;s word count, and assumes an average reading time of 250 words/minute). This got my mind jogging a bit, and after playing around with some geolocation APIs, I thought it&#8217;d be cool to do an app that would give you enough stuff from Longreads to read on your commute.</p>

<p>At the hack day, I ran this past <a href="http://twitter.com/jfkeefe">John Keefe</a>, and we got to talking a bit. He came up with the idea of, instead of limiting it to Longreads, extending the app to any Twitter account&#8212; scrape the links out of a Twitter feed and aggregate the word counts. Then present just enough articles to read on your commute. Since the code behind <a href="http://lab.arc90.com/experiments/readability/">Readability</a> (a bookmarklet to isolate articles from site detritus) is open source, and the HopStop API gives you time estimates for travel time between any two addresses in New York we were in business.</p>

<p>Working with John and the indefatigable <a href="http://twitter.com/erikhinton">Erik Hinton</a> (my former partner in crime at TPM), we built <a href="http://trippyapp.com">Trippy</a> in about 9 hours at the TimesOpen hack day this Saturday. It&#8217;s written in Ruby and Sinatra, and does a lot of cool stuff behind the scenes to get you your articles. Here&#8217;s how it works:</p>

<p>When you put in your origin and destination addresses, it sends them off (via <a href="https://github.com/collectiveidea/delayed_job">delayed_job</a>) to the Google Maps <a href="http://code.google.com/apis/maps/documentation/geocoding/">geocoding API</a> to convert them into latitude and longitudes. (Though, if you click the &#8216;geo&#8217; button, and have GPS enabled, the app can get your origin <a href="https://developer.mozilla.org/En/Using_geolocation">automatically</a>). From there, it passes the lat and long to the <a href="http://www.hopstop.com/freeapi/">HopStop API</a> to get the Subway travel time between the two distances. It then takes the Twitter account or Twitter list (to use a list enter <code>account/list_name</code> in the Twitter account field) and uses the <a href="https://github.com/mzsanford/twitter-text-rb">twitter-text gem</a> to extract the links. From there, it uses the crazy <a href="https://github.com/pauldix/typhoeus">Typhoeus gem</a> to simultaneously evaluate all the short links and suck down all the pages in parallel. It runs them through <a href="https://github.com/iterationlabs/ruby-readability">Readability</a>, grabs the word counts, rejects pages with under 250 words (as these probably aren&#8217;t actually articles), and then presents them in a tidy Instapaper-esque page for you to read on the train. To sweeten the pot, the app is also &#8220;<a href="http://www.alistapart.com/articles/responsive-web-design/">responsive</a>&#8221; or at least &#8220;<a href="http://unstoppablerobotninja.com/entry/on-being-responsive/">switchy</a>&#8221; for different screen sizes. I think it looks pretty good on the iPhone and Android.</p>

<p>By the way, Trippy was one of the <a href="http://open.blogs.nytimes.com/2010/12/06/timesopen-hack-day-wrap-up/">hack day winners</a>, garnering a $200 Amazon gift card (and a role in saving journalism).</p>

<p>So, here it is: </p>

<p><a href="http://trippyapp.com">http://trippyapp.com</a>. </p>

<p>It&#8217;s still buggy, and delayed_job is kinda flaky, so let <a href="http://twitter.com/a_l">me</a> know if it gets stuck on &#8220;processing.&#8221; But the code is up <a href="https://github.com/esmooov/Trippy">here</a>, so if you see a bug, fix it.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>&apos;Election Night at TPM&apos; Presentation at Hacks/Hackers Demo Day </title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/12/election-night-at-tpm-presentation-at-hackshackers-demo-day.php" />
    <id>tag:www.shhhaw.com,2010://1.61</id>

    <published>2010-12-02T04:47:01Z</published>
    <updated>2010-12-02T04:59:42Z</updated>

    <summary>Erik and I gave a 5 minute talk at New Work City tonight on the TPM election night app for Hacks/Hackers Demo Day. Here are the slides: And, just for fun, here&#8217;s one of the static images (for the TPM...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p><a href="http://twitter.com/erikhinton">Erik</a> and I gave a 5 minute talk at New Work City tonight on the TPM election night app for <a href="http://meetupnyc.hackshackers.com/calendar/15400309/">Hacks/Hackers Demo Day</a>.</p>

<p>Here are the slides:</p>

<p><iframe src="https://docs.google.com/present/embed?id=dkxxh2j_11qcf42hg9&size=m" frameborder="0" width="555" height="451"></iframe></p>

<p>And, just for fun, here&#8217;s one of the static images (for the TPM homepage as results came in) generated from the SVG by the svg2png.rb Sinatra app shown on the last slide.</p>

<p><img src="http://election2010.s3.amazonaws.com/H.png" width="555"/></p>
]]>
        

    </content>
</entry>

<entry>
    <title>I Wrote an Intro to Git for A List Apart</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/11/a-git-lesson-apart.php" />
    <id>tag:www.shhhaw.com,2010://1.60</id>

    <published>2010-11-02T12:35:02Z</published>
    <updated>2011-02-22T16:57:35Z</updated>

    <summary>I wrote a &#8220;Get Started with Git&#8221; guide for A List Apart: Version control: It isn&#8217;t just for coders anymore. If you&#8217;re a writer, editor, or a designer who works iteratively on the web and you want to reshuffle or...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="ALA" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="git" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="me" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>I wrote a &#8220;Get Started with Git&#8221; guide for A List Apart:</p>

<blockquote>
  <p>Version control: It isn&#8217;t just for coders anymore. If you&#8217;re a writer, editor, or a designer who works iteratively on the web and you want to reshuffle or combine pieces of your work quickly and efficiently, version control is for you, too. Al Shaw shows us how easy it is to install, set up, and work with Git&#8212;open-source, version control software that offers you much, much, more than just &#8220;undo.&#8221;</p>
</blockquote>

<p>Read the <a href="http://www.alistapart.com/articles/get-started-with-git/">whole thing at ALA</a>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Journo-nerd News</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/10/journo-nerd-news.php" />
    <id>tag:www.shhhaw.com,2010://1.59</id>

    <published>2010-10-21T12:39:33Z</published>
    <updated>2010-10-21T16:34:16Z</updated>

    <summary>A bit of news on the personal front today&#8212; shortly after the election, I will be leaving TPM, where I&#8217;ve been for about two and a half years, first as an intern, then as Associate Publisher and Designer/Developer. Where am...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="ProPublica" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="TPM" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="me" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>A bit of news on the personal front today&#8212; shortly after the election, I will be leaving TPM, where I&#8217;ve been for about two and a half years, first as an intern, then as Associate Publisher and Designer/Developer.</p>

<p>Where am I going?</p>

<p>I have accepted an offer to become a developer on the <a href="http://www.propublica.org/nerds/">news applications desk</a> at <a href="http://www.propublica.org/">ProPublica</a>. The &#8220;nerds&#8221; work to tell stories with software and data-based interactive applications (such as the <a href="http://projects.propublica.org/docdollars/">Dollars for Docs app</a> that dropped this week). They&#8217;re also building new tools to cultivate sources and help other journalists around the country do investigative reporting. Along with giving away their stories and publishing their reporting &#8220;recipes,&#8221; ProPublica also has a strong commitment to releasing their code as <a href="http://github.com/propublica">open source</a> projects, something I believe in strongly. It&#8217;s a really awesome opportunity at the intersection of journalism, programming and design, and I can&#8217;t wait to get started!</p>

<p>I&#8217;ve worked on some incredible projects at TPM, from 2008 election night coverage to a complete redesign and rework of the front page, to <a href="http://polltracker.talkingpointsmemo.com">TPM PollTracker</a> (which might now be the biggest poll aggregator on the web with over 14,000 polls). We also have some <a href="http://dribbble.com/shots/59741-Election-Results-Thermometer">treats</a> <a href="http://dribbble.com/shots/59324-Election-Results-tooltip">in</a> <a href="http://dribbble.com/shots/58023-Election-Results">store</a> for election night 2010. TPM really stands out as one of the best examples of how to do journalism well (and profitably) on the web. Josh has built an amazing organization, which has grown impressively over the time I was there. I&#8217;m so thankful to him and his tireless staff for the opportunity to contribute to its success.</p>

<p>By the way, if you&#8217;ve got the journo-nerd itch and want to do design and dev at TPM, drop a line to <code>talk at talkingpointsmemo dot com</code> with subject line <code>designer/developer</code>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Git Epiphany: Merge is the Opposite of Checkout</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/09/git-epiphany-merge-is-the-opposite-of-checkout.php" />
    <id>tag:www.shhhaw.com,2010://1.57</id>

    <published>2010-09-03T17:14:16Z</published>
    <updated>2010-09-03T17:16:17Z</updated>

    <summary>I was just chatting with Erik &#8220;Heezy&#8221; Hinton about the best way to selectively merge files with Git and started to wrap my mind around Git&#8217;s most misunderstood command, checkout. The conventional wisdom is that git-checkout&#8217;s normal use is for...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="git" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="workflow" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>I was just chatting with <a href="http://twitter.com/erikhinton">Erik &#8220;Heezy&#8221; Hinton</a> about the best way to selectively merge files with Git and started to wrap my mind around Git&#8217;s most misunderstood command, <code>checkout</code>. The conventional wisdom is that <code>git-checkout</code>&#8217;s normal use is for switching branches. If I&#8217;m on <code>master</code>, I could <code>git checkout devel</code> to move to the development branch, or <code>git checkout -b foo</code> to create a new <code>foo</code> branch. This is considered a &#8220;safe&#8221; use of <code>git-checkout</code>. But, as it is written, <code>checkout</code> has a &#8220;destructive&#8221; side as well, which instantly changes content in your current working tree. If you <code>git checkout .</code> after you&#8217;ve saved local changes, it&#8217;ll revert everything in your repo to the state of the last commit. If you <code>git checkout bar.txt</code>, you&#8217;ll just revert that file. Likewise, if you <code>git checkout devel bar.txt</code> you&#8217;ll bring over the development version of bar.txt without concern for the current branch&#8217;s version of it. In this sense, <code>git-checkout</code> treats the current working tree as &#8220;hostile,&#8221; in the face of whatever you&#8217;re bringing into it. </p>

<p>On the contrary, <code>git-merge</code> treats any <em>foreign</em> object as &#8220;hostile&#8221; and protects, at all costs, your current tree. It does whatever it can to prevent you from changing anything in your tree that can&#8217;t be cleanly merged. </p>

<p>This question of &#8220;hostility preference&#8221; is really what sets <code>git-merge</code> and <code>git-checkout</code> apart, and why the commands are actually opposites. To prove it, I&#8217;ll say that it is actually possible to completely emulate <code>git-merge</code> with just <code>git-checkout</code> and <code>git add --patch</code> (which allows you to selectively add parts of files). They actually make this even easier for you with the <code>--ours</code> and <code>--theirs</code> <a href="http://www.gitready.com/advanced/2009/02/25/keep-either-file-in-merge-conflicts.html">flags</a>. When you think about it, <code>git-checkout</code> isn&#8217;t just switching branches, it&#8217;s actually replacing every file in your working tree with another version of it, but keeping a reference to the original. That&#8217;s why there&#8217;s no &#8220;safe&#8221; and &#8220;destructive&#8221; version of this much-misunderstood command, there&#8217;s just the one <code>git-checkout</code>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Better &quot;Most Viewed&quot; Story Lists with Chartbeat and Ruby</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/06/better-most-viewed-story-lists-with-chartbeat-and-ruby.php" />
    <id>tag:www.shhhaw.com,2010://1.55</id>

    <published>2010-06-25T03:33:05Z</published>
    <updated>2010-07-04T00:28:16Z</updated>

    <summary>Since I came across it about a year ago via a posting on Hacker News, I&#8217;ve been a big fan of the Chartbeat real-time analytics service. Last summer, I posted on their official blog about a hack I had come...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>Since I came across it about a year ago via a posting on Hacker News, I&#8217;ve been a big fan of the <a href="http://www.chartbeat.com">Chartbeat</a> real-time analytics service. Last summer, I <a href="http://blog.chartbeat.com/2009/08/04/guest-post-how-talking-points-memo-uses-chartbeat/">posted on their official blog</a> about a hack I had come up with to generate top ten most viewed story lists from their API: Unlike conventional analytics platforms, Chartbeat doesn&#8217;t provide cumulative stats. Instead, their API returns &#8220;<a href="http://chartbeat.pbworks.com/toppages">snapshots</a>&#8221; of how many people are actually sitting on pages when you request the data. I wrote a PHP/SQLite script called stats_combiner that runs on a cron and collects and combines this live data. Every hour, it pushes out its flattened plain HTML list of &#8220;top ten stories.&#8221; </p>

<p>Since then, I&#8217;ve gotten a number of requests to open-source or otherwise describe this solution. So, I rewrote the script in Ruby and have added a number of features since the original PHP implementation. It&#8217;s now <a href="http://github.com/tpm/stats_combiner">available as a gem</a>, and TPM&#8217;s first official open source release. </p>

<p>One of the coolest differences between the gem and the original version is its extensibility. I found I had to keep changing the original script to modify data chartbeat was producing before I could surface it on the live site, such as accounting for subdomains, stripping out query strings and excluding certain records like landing pages and other &#8220;non-story&#8221; pages. The new version of stats_combiner has a Filterer class for setting these rules. Check the <a href="http://github.com/tpm/stats_combiner">README</a> for more about how it works. If you run a content site, this is <em>the</em> easiest way to set up a top ten widget. </p>

<p>Install it with <code>gem install stats_combiner</code>.</p>

<p>Additional shameless plug: stats_combiner 0.0.3 now comes with my brand new <a href="http://github.com/ashaw/chartbeat">chartbeat gem</a> which makes it super easy to access all of the Chartbeat API <a href="http://chartbeat.pbworks.com/">endpoints</a>. 
With the new chartbeat gem, getting a list of the top ten pages readers are perusing right now is two lines of code:</p>

<pre><code>c = Chartbeat.new :host =&gt; 'yourdomain.com', :apikey =&gt; 'yourkey'
c.toppages :limit =&gt; 10
</code></pre>

<p>To get the chartbeat gem, run <code>gem install chartbeat</code>. </p>
]]>
        

    </content>
</entry>

<entry>
    <title>Fourrific is a Foursquare Client for Your Computer</title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/04/fourrific-is-a-foursquare-client-for-your-computer.php" />
    <id>tag:www.shhhaw.com,2010://1.53</id>

    <published>2010-04-05T02:18:43Z</published>
    <updated>2010-04-05T02:23:23Z</updated>

    <summary>I&#8217;ve been a lukewarm Foursquare user for a while, but it wasn&#8217;t until I attended SXSWi last month that I really started getting into it. It&#8217;s an awesome app for when there are a ton of people &#8216;playing&#8217; within a...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="Design" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Fourrific" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Foursquare" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Sinatra" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>I&#8217;ve been a lukewarm Foursquare user for a while, but it wasn&#8217;t until I attended SXSWi last month that I really started getting into it. It&#8217;s an awesome app for when there are a ton of people &#8216;playing&#8217; within a relatively-constrained geographic area. Nevertheless, I brought the checkin habit back with me to New York, where I spend a lot of time sitting at a desk. </p>

<p>At that point, I realized that Foursquare: the Website pales in comparison to Foursquare: the App mainly in that it doesn&#8217;t give you a feed of your friends&#8217; activities. I really wanted a Twitterific-style narrow column that I can keep around on my desktop to see where people have checked in recently without having to pull out my phone.</p>

<p><img src="http://www.shhhaw.com/images/fourrific-sg-crop.png" class="gutter" alt="Fourrific screenshot"></p>

<p>So, in one day of coding (and a couple more for bugfixing, styling and error handling), I built <a href="http://fourrific.shhhaw.com">Fourrific</a>, a really simple Foursquare app.</p>

<p>Fourrific is very <a href="http://daringfireball.net/linked/2010/03/09/taylor">glued-together</a>: it&#8217;s based on Sinatra, my current favorite web framework, and a slough of gems. It authenticates to Foursquare via OAuth, and finds your location through your IP address via <a href="http://geokit.rubyforge.org/">Geokit</a>, though that can be hit-and-miss depending on your ISP (for example, when I&#8217;m at my desk in Chelsea, it thinks I&#8217;m in the Bronx). With that data, it can (very roughly) tell you how far away each person is, gathered from the <code>&lt;distance&gt;</code> node the Foursquare API returns if you pass it latitude and longitude parameters. If Fourrific thinks someone is more than 25 miles away, it will fade out that status, and hide it behind the &#8220;Everywhere&#8221; tab (the default active tab is your current city).</p>

<p>On the frontend, I&#8217;m using the beautiful new open source font <a href="http://www.theleagueofmoveabletype.com/fonts/14-raleway">Raleway</a> from the League of Movable Type (embedded with @font-face), and the HTML5 <code>&lt;time&gt;</code> element, which the jQuery plugin <a href="http://timeago.yarp.com/">Timeago</a> can latch onto, to generate relative dates.</p>

<p>Of course, the source is <a href="http://github.com/ashaw/fourrific">available on Github</a> with installation instructions if you&#8217;d like to fork or run your own instance. Though, to just start using it, go to: </p>

<p><a href="http://fourrific.shhhaw.com">http://fourrific.shhhaw.com</a></p>

<p>and log in through OAuth. There is no database whatsoever, so none of your information is stored on the server, and the session cookie only lasts until you quit your browser or revoke your OAuth token. </p>

<p>Check it out, on your <em>computer</em>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Introducing Homer: The Blogware-agnostic Feed-based Homepage Creator for the &apos;News Blob&apos; </title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/03/introducing-homer-the-blogware-agnostic-feed-based-homepage-creator-for-the-news-blob.php" />
    <id>tag:www.shhhaw.com,2010://1.51</id>

    <published>2010-03-09T04:11:43Z</published>
    <updated>2010-03-10T05:19:34Z</updated>

    <summary>Adrian Holovaty, in his post &#8220;A fundamental way newspaper sites need to change,&#8221; writes (emphasis mine): So much of what local journalists collect day-to-day is structured information: the type of information that can be sliced-and-diced, in an automated fashion, by...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="Future of News" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Homer" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Sinatra" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p>Adrian Holovaty, in his post &#8220;<a href="http://www.holovaty.com/writing/fundamental-change/">A fundamental way newspaper sites need to change</a>,&#8221; writes (emphasis mine):</p>

<blockquote>
  <p>So much of what local journalists collect day-to-day is structured information: the type of information that can be sliced-and-diced, in an automated fashion, by computers. Yet the information gets distilled into a <em>big blob of text</em> &#8212; a newspaper story &#8212; that has no chance of being repurposed.</p>
</blockquote>

<p>He has a point, and goes on to explain why we need a CMS that can hold semantic structured data because journalism on the web should be more than just blobs of text.</p>

<div class="meat_meta guttercaption">
A Git &#8220;blob&#8221; object is nothing but a chunk of binary data.
</div>

<p>This is totally correct, and the rapid proliferation of <a href="http://blog.apps.chicagotribune.com/">news apps</a> and <a href="http://www.texastribune.org/">data-driven news organizations</a> is an awesome thing, especially when it lets you do stuff like put in a zip code and see if the <a href="http://projects.nytimes.com/toxic-waters/polluters/">water you&#8217;ve been drinking is toxic</a>, or how many people have been mugged in the last week <a href="http://www.everyblock.com/">on your block</a>. But it also negates (or rather maybe tries to actively obsolesce) something very fundamental to journalism: the story. Holovaty says in the article: &#8220;Newspapers need to stop the story-centric world-view.&#8221; My question to this is, why? </p>

<p><img src="http://www.shhhaw.com/images/git-blob.png" alt="Git Blob" class="gutter"></p>

<p>There will always be a &#8220;news blob&#8221;&#8212; the fundamental block of data that every piece of news has, and every blogging system can handle: a title (headline), a body (story) and a permalink. Bylines and photos are important too, but they can, in a sense, be subsumed into these three primary types. We&#8217;ve been so blinded by data, that we&#8217;ve lost sight of the humble blob. Why is Twitter so popular? Because they&#8217;ve figured out how to <a href="http://37signals.com/svn/posts/2106-you-can-always-do-less">distill</a> these elements down to just one field, and limit the amount you can put into it.</p>

<p>The idea of a blob is so great because it can be anything. In a version control system like Git, a blob is just a bunch of text. It doesn&#8217;t care what you&#8217;re writing or how you organize it. It doesn&#8217;t even have awareness of <em>files</em>, but it can <a href="http://book.git-scm.com/1_the_git_object_model.html">handle whatever you throw at it</a>. When you&#8217;re on deadline, you need software that thinks like Git, that can handle the blob you&#8217;re throwing at it.</p>

<h3>Why Write a CMS?</h3>

<p>A big skill you grapple with as a newbie software developer is how to recognize solved problems. If you squint, there is usually an opportunity for a new app in the cracks between them. A while back there was a hilarious <a href="http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454">response on StackOverflow</a> to a user who was asking for help parsing HTML with regular expressions. While the verbose answer is incredible, the simple answer is <em>you don&#8217;t</em>&#8212; you use a library to consume HTML. It&#8217;s a solved problem.</p>

<p>From a news point of view, getting story data from a writer and keeping it in a database is a solved problem. There is excellent free software out there that does this much better than I could ever hope to. What blogware does not do well is arrange stories hierarchically. Where Holovaty is right is that these blobs (and 99% of news on the web now is in blob-form) need to be <em>repurposed</em>, because blogware isn&#8217;t designed with news judgement in mind. This is why I wrote Homer. Homer is for news homepages.</p>

<h3>How it works</h3>

<p>Homer works through XML feeds, which I, yes, use a <a href="http://rubygems.org/gems/feedme">library</a> to parse. Stories from those feeds can then be assigned to <strong>slots</strong> which live at arbitrary places on your homepage that you place where you want and label semantically. Once there, stories can be moved between slots or unassigned into oblivion. In a sense, Homer is a blog disaggregator. It allows you to add as many feeds as you want, and cherry-pick stories from them to live in your homepage until you bump them for other stories. It is transient, where blogware plans for permanence. It is serendipitous, where blogware plans for order. It is hand-curated, where blogware rewards predictability and automation. It is hierarchical, where blogware is chronological. Homer is to WordPress as <a href="http://informationarchitects.jp/the-tputh-part-i/">TPUTH</a> is to TechCrunch. In short, they work well together. To steal the tagline from <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>, Homer is the tie to (Movable Type|WordPress|Tumblr|ExpressionEngine)&#8217;s tux. </p>

<p>While you can use Homer to &#8220;curate the web&#8221; because all you need to add a feed is its URL, its newsroom use case is to serve as your homepage and hand-arranged topic pages, sitting atop a sea of template-generated back pages.</p>

<p>Here&#8217;s how you use it:</p>

<p><img class="gutter" alt="Starting Page" src="http://www.shhhaw.com/images/starting-page.jpg"></p>

<p>The home page of Homer shows lists of the two basic objects in the app, homepages and feeds. Incidentally, these two objects have a <code>has_and_belongs_to_many</code> relationship in the database, so they can be reused. In other words, a feed can be used on as many homepages as you&#8217;d like after entering its title and URL once. The home page shows you the raw material you&#8217;ll use to construct your pages. The edit/delete nubbins allow you to change the file paths and titles of your homepages and titles/urls of feeds. </p>

<p><img class="gutter" alt="Manage Homepage" src="http://www.shhhaw.com/images/manage-page.jpg"></p>

<p>The Manage page is where all the action happens in Homer. This is where you define slots for your homepage, assign feeds to your homepage, assign stories to slots, and rearrange stories within slots. Let&#8217;s look at each of these features in order:</p>

<p><strong>Slots</strong>: When you create a new homepage, you&#8217;ll first want to create your slots. There is no inherent style to default Homer homepages, so you can be free to devise your own hierarchy. A <code>feature</code> might be the top story. Then a <code>subfeature</code>. Or maybe define them by location: <code>left</code>, <code>middle</code>, <code>right</code>. When you get to templating, Homer will auto-generate code to surface slots based on their labels. At this point, slot labels can&#8217;t be edited.</p>

<p><img class="gutter" alt="Slot Creation" src="http://www.shhhaw.com/images/slot-creation.jpg"></p>

<p><strong>Feeds</strong>: The feed menu allows you to assign/remove feeds from the general pool to this homepage. Once they have been assigned, they&#8217;ll show up in the left menu to be &#8220;refreshed&#8221; whenever you want a selection of stories to put into slots. </p>

<p><img class="gutter" alt="Feed Chooser" src="http://www.shhhaw.com/images/feed-chooser.jpg"></p>

<p><strong>Assignment</strong>: There are two kinds of assignment in Homer: Assignment from feed stories to slots, and rearranging stories within slots. When you refresh a feed, its latest stories will show up in a yellow area on the right side of the screen. You can refresh multiple feeds at the same time, and they will all be mixed into that area. From there you can edit the titles, bodies and permalinks (click the down arrow next to the title to reveal the other fields) and assign them to slots via the dropdown menus. Once a story has been assigned to a slot, it will show up in a grey area at the top of the page with the dropdown already filled in for the slot it is currently assigned to. If you assign a story to an already-filled slot, it will &#8220;bump&#8221; that story in favor of your new story. Once your story is assigned, you can move it around by changing the slots in the dropdowns, and hitting save. Assigning a story to the &#8220;blank&#8221; option will unassign it. </p>

<p>The assignment system is built with <em>transience</em> in mind. It is built for the present, <a href="http://www.rollingstone.com/nationalaffairs/index.php/2007/11/03/the-fierce-urgency-of-now/">the fierce urgency of the now</a>. Call it opinionated software. Only the last 5 entries in a feed will be available when refreshed, and once a story has been unassigned, it is all but gone from the system. But don&#8217;t be afraid of this&#8212; your blogware of choice is good at keeping archives, and hopefully it will give you an automatically generated list of your posts somewhere. Homer is for bumping stories at will. A good workflow may be refreshing your feed, then assigning a battery of stories to your slots in the morning. Then cycling stories down the slots while putting new stories in the top slot until they fall off the page a la Techmeme-style aggregators. If you must get a story back, try refreshing the feed from which it came and reassigning it. Homer doesn&#8217;t support dredging up bumped stories for reassignment because no one likes old news.</p>

<p><img class="gutter" alt="Templating" src="http://www.shhhaw.com/images/templating.jpg"></p>

<p><strong>Templating</strong>: While Homer won&#8217;t style your homepages for you, it will provide you with boilerplate code to start you off. After you&#8217;ve created all your desired slots, click on the <code>Template</code> button at the top of the page. You should see a bunch of code already in your editor. You&#8217;ll get a stock HTML wrapper, and for every slot, you&#8217;ll get one of these, assuming your slot is called <code>feature</code>:</p>

<pre><code>&lt;div id="feature"&gt;
 &lt;% @feature = Ho.new(@homepage,'feature') %&gt;
 &lt;h2&gt;&lt;a href="&lt;%= @feature.url %&gt;"&gt;&lt;%= @feature.title %&gt;&lt;/a&gt;&lt;/h2&gt;
 &lt;p&gt;&lt;%= feature.body %&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>

<p>The wrapper is a standard html <code>div</code>, and inside are slot-specific variables. Ho is the templating class for Homer, and line 2 uses it to instantiate a new slot on the page. Once you have done that, you can use the new variable, in this case <code>@feature</code> to output that slot&#8217;s attributes wherever you want. Homer uses ERB (<a href="http://ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html">Embedded Ruby</a>) to output variables, so anything within <code>&lt;%</code> and <code>%&gt;</code> will be parsed as Ruby code. In the boilerplate, <code>@feature.url</code> is wrapped around <code>@feature.title</code>, followed by <code>@feature.body</code> in a paragraph block. You can, however, edit the code to output these variables wherever you want, as long as you instantiate the slot first. If you&#8217;d like, you can move all of the slot inits to the top of the page and out of the markup. Also, as of now, unless you have access to your server&#8217;s filesystem, you&#8217;ll need to write all your style inline much like you do with Tumblr templates.</p>

<p><strong>Aside&#8212; A few thoughts (caveats) on templating and Ruby DSLs</strong>: This is really only a first stab at a good templating language for Homer. I had a <a href="http://gist.github.com/306573">few more syntax ideas</a>, and am still mulling the best way of doing it. Admittedly my current implementation is crufty. Ruby is <a href="http://www.themomorohoax.com/2009/02/25/how-to-write-a-clean-ruby-dsl-part-2-line-by-line-with-machinist-rails">really good</a> for creating Domain Specific Languages (Sinatra itself is a good example), and I need to read up on best practices. This will be a major focus for the next version of Homer. </p>

<p>Once you have the code the way you like it, hit Save. This will also create a file in the filesystem at <code>homer/templates/your_homepage.erb</code> (the path to this template is also shown at the top of the template editor to encourage you to edit in a text editor) because storing templates in a database <a href="https://twitter.com/kleinmatic/status/9600822192">sucks</a>. Once you save (or save from your text editor), you can preview your new homepage design at any time and publish it to the world.</p>

<p><strong>Previewing and Publishing</strong>:</p>

<p>Finally, the fun part where all your hard work pays off. Previewing your homepage will give you a new window where you can see exactly what your page will look like to the outside world. Publishing will write your homepage out to the place in the filesystem you defined when creating it. This should be some place that serves static files, like an Apache Document Root. When you publish, the homepage you direct your audience to is 100% static, so load is basically a nonissue. Homer will do its best to resolve permissions issues when you set up the path, but it may not be able to publish if it doesn&#8217;t have access to the directory, so plan accordingly.</p>

<p>That&#8217;s basically it. It&#8217;s a fun news app for writing static homepages from feeds.</p>

<h3>Under the Hood, and Philosophy</h3>

<p>Homer is written in Ruby with <a href="http://www.sinatrarb.com/">Sinatra</a> and <a href="http://ar.rubyonrails.org/">ActiveRecord</a>. Since starting <a href="http://www.shhhaw.com/2009/12/tpm-on-rails-building-a-news-app-in-under-two-months.php">the TPM PollTracker</a>, I&#8217;ve been <a href="http://www.shhhaw.com/2009/10/first-impressions-of-rails-and-what-it-means-for-online-news.php">smitten</a> with Rails-style development. ActiveRecord, for database interaction, might be one of my favorite pieces of software ever. One thing I hate about Rails, though, is how it does routing. Sinatra connects controller actions directly to URLs, which is much easier for me to wrap my head around. It also doesn&#8217;t impose a filesystem structure for your app. In fact, the only thing it assumes is that you are writing something in Ruby that uses URLs. That&#8217;s just the right amount of opinionation for me. Maybe Rails 3 will allow me to pick and choose how much framework I want, but for now Sinatra + AR gets me 90% of the way there.</p>

<p><img src="http://www.shhhaw.com/images/Laszlo-Moholy-Nagy-Kompozic.png" class="gutter"></p>

<p>With Homer, I&#8217;m also putting my stake in the ground for a few principles and (what I believe to be) best practices in CMS design: </p>

<p><strong>First, you host it yourself.</strong> Movable Type and WordPress have blazed the trail for casual users to self-install server-based web apps, and the fact that this has been catching on is a <a href="http://www.shhhaw.com/2009/09/on-the-merits-of-running-ones-own-blogging-software.php">Good Thing</a> for a number of reasons: less reliance on third parties to be good stewards of your data, demystification of how web-based software works, and more agency given to the end user are a few of them. <a href="http://haveamint.com/">Mint</a> and <a href="http://feedafever.com/">Fever</a> are good examples of how this is becoming a viable distribution method with PHP and mySQL apps. My hope is that the <a href="http://www.loudthinking.com/posts/21-the-deal-with-shared-hosts">Ruby stack will continue to evolve</a>, so Ruby-based software will become as <a href="http://codex.wordpress.org/Installing_WordPress#Famous_5-Minute_Install">easy to install as WordPress</a>.</p>

<p><strong>Second, it&#8217;s open source.</strong> Homer is built on open source software, and the Ruby community lives on free open source software. I&#8217;m a big believer in it.</p>

<div class="meat_meta guttercaption">
Above: László Moholy-Nagy&#8217;s Kompozicija Z VIII (1924). Moholy-Nagy is the patron saint of Homer.
</div>

<p><strong>Third, it generates static pages.</strong> Caching sucks. I&#8217;ve spent an inordinate amount of time on PollTracker working on caching, and even moving hosts over it. While most people agree that static pages are the best way to serve content (no one can disagree that it is the fastest), there are different approaches on how best to generate them (and how to expire them). For sites with a large number of pages, I like the Rails page caching method: expire data when it is changed, and give the brunt of caching each page to its first visitor. This makes deployment easy, and allows you to roll out a global change instantly. Movable Type does the opposite: it generates static pages at time of publish. This puts the brunt of publishing wait on the author, and also makes it very difficult to <a href="http://www.shhhaw.com/2009/09/mt-gitpub-my-tool-to-deploy-mt-templates-from-git.php">roll out template changes</a> across an entire site. For one page, though (one that is assumed to be constantly changing), I prefer this method. It also means that the outward-facing server doesn&#8217;t have to run the slow Ruby stack at all, and no caching has to be done within the app itself. </p>

<p><strong>Fourth, the templates are files.</strong> They aren&#8217;t stored in the database. This is one area where WP (and most web frameworks) have a leg up on MT and EE. The database should be used to populate template variables, and store as little markup as possible. Storing templates in the database makes them tough to republish, and makes it really difficult to edit them in a text editor, unless you want to do a lot of copy and pasting.</p>

<h3>Inspirations</h3>

<p>Where did I get this idea? A couple different things gelled into me needing to write this app. The first was a lunch I had with <a href="http://www.propublica.org/site/author/scott_klein">Scott Klein</a> of ProPublica a few months ago, where we talked about CMS design and basically agreed it is a mistake to <a href="https://twitter.com/kleinmatic/status/9263095098">develop against your CMS</a>. ProPublica uses ExpressionEngine for their stories, and spins up EC2 instances for their Rails apps. They integrate the two mostly through style. Homer works along these lines, and Scott got me thinking down that path. </p>

<p>Secondly, I was inspired by two Movable Type plugins from SixApart. The first, SqueezePlay (which unfortunately has not been open-sourced) is a homepage manager that uses the story assignment/slot metaphor, and is what we use at TPM to handle our front page. The other is <a href="http://github.com/sixapart/movable-type-reblog">Reblog</a>, an awesome MT plugin that parses RSS feeds into MT entries. Homer is kind of SqueezePlay + Reblog, but <em>outside</em> the CMS. </p>

<p>Thirdly, a group of my friends from the University of Chicago are starting a new (as of yet unreleased) online magazine, albeit a &#8220;deconstructed&#8221; magazine which will collect content from a wide variety of sources and contributors and mash it together. This provided an initial use case that spurred development. Since I was developing Homer for free, I decided to <a href="http://github.com/ashaw/homer">open-source</a> it as a community journocoding project. I hope it will prove useful to others!</p>

<h3>Get it!</h3>

<p>To install Homer, first make sure you have a newish version of Ruby&#8212; 1.8.6 and higher is required for the current version of Rubygems (1.3.6). Then <a href="http://rubygems.org/pages/download">install Rubygems</a>, and <code>gem install sinatra activerecord sqlite3-ruby feedme</code>. Now you&#8217;re ready to install Homer.</p>

<p>If you have git, just</p>

<pre><code>git clone git://github.com/ashaw/homer.git
cd homer/bin
./homer init //to set up SQLite db and templates dir
./homer run
</code></pre>

<p>then open a browser to http://localhost:4567</p>

<p>or grab the <a href="http://github.com/ashaw/homer/tarball/master">tarball</a> or <a href="http://github.com/ashaw/homer/zipball/master">zipball</a>, uncompress and start at step 2 above. </p>

<p>To install on an Apache web server, the best way is to install the <a href="http://rubygems.org/gems/passenger">Phusion Passenger gem</a>, follow the instructions to set it up, and make a VirtualHost for Homer, like so (I recommend setting up a password in htpasswd for Homer since the app doesn&#8217;t support authentication):</p>

<pre><code>&lt;VirtualHost *:80&gt;
     ServerName homer.yourdomain.com
     DocumentRoot /var/www/homer/public
     &lt;Directory /var/www/homer/public&gt;
        AllowOverride all
        Options -MultiViews
        AuthType Basic                  
        AuthName "Restricted"
        AuthUserFile /var/www/yourpasswords
        Require user youruser
     &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</code></pre>

<p>To start and restart the app, just <code>touch tmp/restart.txt</code> from your Homer root directory, don&#8217;t <code>homer run</code>, Passenger will take care of the rest.</p>

<p>Obviously, this is still very much alpha (perhaps pre-alpha) software, so act accordingly. I&#8217;d love to get your feedback, <a href="http://github.com/ashaw/homer/issues">bug reports</a>, comments, etc. And you should follow me on twitter <a href="http://www.twitter.com/a_l">here</a>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Behind the New Big Calendar Front Page Style on TPM PollTracker </title>
    <link rel="alternate" type="text/html" href="http://www.shhhaw.com/2010/01/behind-the-new-big-calendar-front-page-style-on-tpm-polltracker.php" />
    <id>tag:www.shhhaw.com,2010://1.48</id>

    <published>2010-01-28T03:37:01Z</published>
    <updated>2010-01-28T03:50:57Z</updated>

    <summary> Below: Massimo Vignelli&#8217;s Perpetual Calendar Today I deployed a new look to the front page, monthly archive pages and individual poll pages on TPM PollTracker. The new look gives more focus to dates, so you can quickly scan all...</summary>
    <author>
        <name>Al Shaw</name>
        
    </author>
    
        <category term="Design" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Rails" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="TPM" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.shhhaw.com/">
        <![CDATA[<p><img src="http://www.shhhaw.com/images/vignelli-calendar-list-style.jpg" alt="New Big Calendar List Style"></p>

<div class="meat_meta guttercaption">
Below: Massimo Vignelli&#8217;s Perpetual Calendar
</div>

<p>Today I deployed a new look to the front page, monthly archive pages and individual poll pages on <a href="http://polltracker.talkingpointsmemo.com">TPM PollTracker</a>. The new look gives more focus to dates, so you can quickly scan all the polls that ended on a certain day. The design itself was inspired by Massimo Vignelli&#8217;s <a href="http://www.cooperhewittshop.org/?path=item&amp;topid=7&amp;itemid=263">Perpetual Calendar</a>&#8212; one of my favorite pieces of design ever.</p>

<p><img src="http://www.shhhaw.com/images/vignelli-perpetual-calendar-crop.jpg" class="gutter" alt="Vignelli Perpetual Calendar"></p>

<p>With the thought that the day of the month needed to be big, a couple problems presented themselves. This is a case where Cascading Style Sheets and their float model needed to coexist with tables, but sticking a &#8220;big cal&#8221; day in a cell would necessarily stretch out the whole data row to the height of the date, even if there is more than one poll on a given day. By the same token, what to do about days with only one poll&#8212; wouldn&#8217;t the dates run into each other if they were smushed to the height of the data row?</p>

<p>Before even addressing this question, I needed a way to find the latest poll of a given day, and show the date in the left column of just that poll. This was tougher than it looks. Here&#8217;s the <code>first_dates</code> method I came up with:</p>

<pre><code>class Poll &lt; ActiveRecord::Base
    def self.first_dates(polls)

        first_polls_of_days = []

        p = polls
        p = p.collect {|q| [q.id, q.end_date]}          

        uniq_dates = p.collect {|s| s[1]}.uniq

        (0..((uniq_dates.size) - 1)).each do |date|
            first_polls_of_days &lt;&lt; p.select{|a| a if a[1] == uniq_dates[date]}[0][0]
        end

        return first_polls_of_days
    end
end
</code></pre>

<p>This method takes an array of polls as its argument (which are the polls delivered by <code>will_paginate</code> as all the polls to show on a given page). It collects each of these polls and filters out everything but the id and the end_date. Then it creates another array of unique dates in the given set of polls. Finally, it matches up the first poll it finds for a given date and returns and array of &#8220;first date&#8221; poll ids.</p>

<p>Then in my view, there is a simple condition:</p>

<pre><code>&lt;% if @first_dates.include?(poll.id) %&gt;
    &lt;!-- show the "big cal" --&gt;
&lt;% end %&gt;
</code></pre>

<p>So, that covers the cool date look for each set of polls, but what about the second problem, where the first poll row would be too high as a result of the &#8220;big cal&#8221; date? I solved that with a little bit of CSS and Ruby trickery. First, the CSS issue: the reason the row was stretching out was because the computed height of the row was dependent on the big size of the date. If I tricked the browser into believing the <code>&lt;h2&gt;</code> that contained the &#8220;big cal&#8221; number was actually 0 height, it would defer to the computed height of the data row:</p>

<pre><code>.big_date h2.multi {
      height:0 !important;
  }
</code></pre>

<p>But then, if there was a row with only one poll on a given day, the date would run into the row below it. That row should <em>not</em> have the <code>multi</code> class. In that case, we don&#8217;t care that the day takes up its rightful height, and even prefer that the row is a little larger to accommodate the &#8220;big cal&#8221; date. </p>

<div class="meat_meta guttercaption">
Right: Problems: not enough space, and too much space for &#8220;big cal&#8221; dates. Luckily polls_per_day came to the rescue.
</div>

<p><img src="http://www.shhhaw.com/images/vignelli-calendar-list-style-problems.jpg" alt="Big Cal Style Problems"></p>

<p>To solve this, I wrote another model method:</p>

<pre><code>class Poll &lt; ActiveRecord::Base
    def self.polls_per_day(polls,end_date)
        p = polls
        p = p.collect {|q| q.end_date}
        polls_on_date = p.select {|a| a == end_date}

        return polls_on_date.size
    end
end
</code></pre>

<p>The <code>polls_per_day</code> method takes the same poll array and a specific end_date as its arguments, and then just returns how many polls there are on a certain day. </p>

<p>NB: I&#8217;m making use of the same <code>polls</code> array over and over rather than leaning on <code>Poll.find()</code> to avoid spendy database queries. As a result, these methods are not that expensive at all.</p>

<p>In my view, I just check to see if <code>polls_per_day</code> is greater than 1. If so, I&#8217;ll add the <code>multi</code> class:</p>

<pre><code>&lt;h2 &lt;% if Poll.polls_per_day(@polls,poll.end_date) &gt; 1 %&gt;class="multi"&lt;% end %&gt;&gt;
</code></pre>

<p>It&#8217;s a really cool effect, and makes the PollTracker front page that much shinier.</p>
]]>
        

    </content>
</entry>

</feed>