<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>e;feed</title>
    <link>http://ericrichardson.com/</link>
    <description>Talk of life and technology with Eric Richardson.</description>
<item>
  <title>Starting a New Chapter and Moving East</title>
  <guid>http://ericrichardson.com/2012/05/1797-starting-a-new-chapter-and-moving-east</guid>
  <link>http://ericrichardson.com/2012/05/1797-starting-a-new-chapter-and-moving-east</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>    &lt;img src="http://ericrichardson.com/ah/i/fe8106fecda27c8878ac86f624fd5ff6/4248-wide.jpg" width="620" height="391" alt="Piedmont Park and the Skyline" /&gt;

    &lt;p&gt;&lt;i&gt;The Atlanta skyline as seen from Piedmont Park, a 189-acre green space near midtown. ()&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;It has been a whirlwind month for Kathy and me, starting with a vacation back east and culminating with my last day at KPCC just over one week ago. Next month we'll be backing our bags and moving to Atlanta after a decade here in L.A.&lt;/p&gt;

&lt;p&gt;Yesterday I bought the plane tickets: our time as Angelenos ends at 1:10pm on June 15.&lt;/p&gt;
&lt;p&gt;Moving back east is a thought that we had entertained for a while, since we don't have any family out here on the west coast. Once Kathy decided that she wasn't going to be returning to her school next year, the conversation about where we might want to be started in earnest.&lt;/p&gt;

&lt;p&gt;We went back to South Carolina for Kathy's spring break, and while there decided that we were serious enough about the idea of Atlanta as a possible destination that I should start looking into companies who might be hiring.  I sent off a few resumes, and ended up setting two interviews for a day that we would be passing through before flying back out west.  Both turned into offers, and a week later I turned in my notice to the station and we began the process of planning a move.&lt;/p&gt;

&lt;p&gt;Last Monday I started my new job with &lt;a href="http://emcien.com/"&gt;Emcien&lt;/a&gt;, a company that has a suite of applications built around really fast pattern matching in large data sets.  While I won't be going anywhere near the math itself—I had to admit during my interview that my last math class was my junior year of high school—I'm really intrigued by the challenges that come in building the applications that allow users to make effective use of their data and the results that come out of it.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogdowntown.com"&gt;blogdowntown&lt;/a&gt; stays at KPCC, where it hopefully has a long life ahead of it.  My day-to-day involvement in the site ended back in January, so our move won't create much of a change there.  I'll continue to be involved with the open-source development of &lt;a href="https://github.com/AssetHost/AssetHost"&gt;AssetHost&lt;/a&gt; and &lt;a href="https://github.com/StreamMachine/StreamMachine"&gt;StreamMachine&lt;/a&gt;, the visual asset handling and audio streaming systems I wrote while there.&lt;/p&gt;

&lt;p&gt;There's a lot that we'll miss here in L.A., but we're excited to head out on a new adventure.  Unfortunately, that adventure starts with logistics: this week I get to start calling movers.&lt;/p&gt;
</description>
  <pubDate>Mon, 14 May 2012 07:08:26 -0700</pubDate>
</item>
<item>
  <title>Making Sense of Numbers</title>
  <guid>http://ericrichardson.com/2012/05/1796-making-sense-of-numbers</guid>
  <link>http://ericrichardson.com/2012/05/1796-making-sense-of-numbers</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>    &lt;img src="http://ericrichardson.com/ah/i/0df7212322f141fe0eb6bac8bbba0bb8/4247-wide.jpg" width="587" height="400" alt="StreamMachine Cubism Graphs" /&gt;

    &lt;p&gt;&lt;i&gt;Graphs of listener data powered by Cubism (Eric Richardson)&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;After several partial-deployment tests, we launched &lt;a href="http://github.com/SCPR/StreamMachine"&gt;StreamMachine&lt;/a&gt; at KPCC on Tuesday evening, putting &lt;a href="http://www.scpr.org/listen_live/"&gt;online listeners&lt;/a&gt; in the hands of a Node.JS app that &lt;a href="http://ericrichardson.com/2012/01/1778-getting-over-the-hump-with-node"&gt;I barely figured out how to start writing back in January&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There have been a few hiccups—I don't think people with Roku boxes are very happy at the moment—but on the whole it's been a very successful launch.&lt;/p&gt;

&lt;p&gt;While audio streaming provides a number of interesting challenges—how do you handle deployment of new app versions when your connections are of indefinite length, for instance—I'm really interested to play with ways of visualizing listener behavior and interactions.&lt;/p&gt;
&lt;p&gt;For the StreamMachine launch I'm using a pair of really interesting open source packages put out recently by &lt;a href="https://squareup.com/"&gt;Square&lt;/a&gt; to enable real-time analysis of listening patterns.  &lt;a href="http://square.github.com/cube/"&gt;Cube&lt;/a&gt; is a datastore built on top of MongoDB that's designed specifically for time-series data.  &lt;a href="http://square.github.com/cubism/"&gt;Cubism&lt;/a&gt; is a visualization plugin using &lt;a href="http://d3js.org/"&gt;d3&lt;/a&gt; that then turns that data into interesting visuals.&lt;/p&gt;

&lt;p&gt;Traditional logging for a listening stream doesn't make for a very good event.  Saying that a listener completed a 45-minute streaming session at 6:55pm is great, but that data point needs to be spread out over the whole listening period to give a true picture.&lt;/p&gt;

&lt;p&gt;But what if instead you logged every minute listened as it was listened?  You would end up with a series of events taking place at the right time in the timeline, and you could then analyze them as they're still in progress.&lt;/p&gt;

&lt;p&gt;The screenshot above shows the results, which gives a snapshot of all listening, a comparison to yesterday's stats, and a view of KPCC app listening vs some in-browser numbers.  Refining the options and presentation is a work-in-progress, but already it's a fascinating live view of what's going out of our servers.&lt;/p&gt;
</description>
  <pubDate>Thu, 03 May 2012 22:02:12 -0700</pubDate>
</item>
<item>
  <title>Authenticating a Google Service Account</title>
  <guid>http://ericrichardson.com/2012/04/1795-authenticating-a-google-service-account</guid>
  <link>http://ericrichardson.com/2012/04/1795-authenticating-a-google-service-account</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>&lt;p&gt;I spent a few hours at work today trying to make sense of Google's new &lt;a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount"&gt;OAuth2 service accounts&lt;/a&gt;, implementing code to generate the JSON Web Token it wants and then query Google's auth server to get the OAuth token. Google intends the accounts to be used by backend services, which makes a lot more sense than shoe-horning them into access via some user's account as is normally the case.&lt;/p&gt;

&lt;p&gt;Only after I had all that and I tried to make an API request did I realize that Google doesn't support service accounts in Analytics yet, so all of that work was in vain.  To try to keep it from going to waste, I figured I would post it here.  Looking to authenticate a Google service account  for a Ruby app? Hopefully this will save you a little time.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/progrium/ruby-jwt"&gt;JWT gem can be found here&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'jwt'

# -- Create JWT -- #

# load in private key
keydata = nil
File.open(Rails.root.to_s+"/config/google_api_key.p12",:encoding =&amp;gt; "binary") {|f| keydata = f.read(); }
pk = OpenSSL::PKCS12.new(keydata,"notasecret")

# generate the JWT
jwt = JWT.encode({
  :iss    =&amp;gt; "12345678@developer.gserviceaccount.com",
  :scope  =&amp;gt; "https://www.googleapis.com/auth/someservice.readonly",
  :aud    =&amp;gt; "https://accounts.google.com/o/oauth2/token",
  :exp    =&amp;gt; (Time.now + 3600).to_i,
  :iat    =&amp;gt; Time.now.to_i
},pk.key,"RS256")

# -- Convert into an OAUTH2 Token -- #

uri = URI("https://accounts.google.com/o/oauth2/token")
req = Net::HTTP::Post.new uri.path
req.set_form_data(:grant_type =&amp;gt; "assertion", :assertion_type =&amp;gt; "http://oauth.net/grant_type/jwt/1.0/bearer", :assertion =&amp;gt; jwt)

conn = Net::HTTP.new uri.host, uri.port
conn.use_ssl = true

resp = conn.start do |http|
  http.request(req)
end

json = JSON.parse(resp.body)

# token is at json['access_token']
puts json
&lt;/code&gt;&lt;/pre&gt;
</description>
  <pubDate>Thu, 26 Apr 2012 15:34:34 -0700</pubDate>
</item>
<item>
  <title>Scratching your own itch...</title>
  <guid>http://ericrichardson.com/2012/04/1794-scratching-your-own-itch</guid>
  <link>http://ericrichardson.com/2012/04/1794-scratching-your-own-itch</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>    &lt;img src="http://ericrichardson.com/ah/i/316ecbf827f565a8dd756b1e769e7b89/4246-wide.jpg" width="620" height="358" alt="KPCC To Go App Screenshot" /&gt;

    &lt;p&gt;&lt;i&gt;My proof-of-concept "KPCC To Go" app in front of the Xcode development environment. (Eric Richardson)&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;It feels nice to be able to build something that scratches your own itch, even if it may be one that no one else has.  This morning I commuted to work while listening to some "nearly live" radio via a small iPhone app that I put together to work with &lt;a href="http://github.com/SCPR/StreamMachine/"&gt;StreamMachine&lt;/a&gt;, my experiment in next-gen streaming audio server.&lt;/p&gt;

&lt;p&gt;While we &lt;a href="http://ericrichardson.com/2012/03/1788-taking-radio-beyond-the-play-button"&gt;didn't get picked to receive the grant I wrote about a few weeks ago&lt;/a&gt;, I've been saying for several months now that I really wanted an app to let me grab a commute's worth of audio just before I walked out the door and onto the subway.&lt;/p&gt;
&lt;p&gt;Last night, I finally got the app to the point where I could do just that.  The server side of things has been in place since mid-February, but the app side of things kept running into the fact that I don't know Objective-C and have never put the time into getting up to speed on iOS app development.&lt;/p&gt;

&lt;p&gt;That point kept being hammered home to me over the weekend as I again and again ran into variations of the &lt;code&gt;EXC_BAD_ACCESS&lt;/code&gt; error as I tried to reference things that I was inadvertently failing to keep in memory.&lt;/p&gt;

&lt;p&gt;Last night I finally refactored my way past that and got the app working.&lt;/p&gt;

&lt;p&gt;Then this morning I pushed the "Grab New Audio!" button a few minutes before walking out the door and quickly had the last fifty minutes of live radio to listen to as I navigated the Red and Gold lines—a route that has both periods of no data connection and connectivity losses.&lt;/p&gt;

&lt;p&gt;It may just be a proof-of-concept, but it worked like a champ for me.&lt;/p&gt;
</description>
  <pubDate>Wed, 25 Apr 2012 19:04:42 -0700</pubDate>
</item>
<item>
  <title>Extra terabytes</title>
  <guid>http://ericrichardson.com/2012/04/1793-extra-terabytes</guid>
  <link>http://ericrichardson.com/2012/04/1793-extra-terabytes</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>    &lt;img src="http://ericrichardson.com/ah/i/69547886dea7d5aa2546161d757696ea/4245-wide.jpg" width="620" height="272" alt="Terabyte Hard Drive" /&gt;

    &lt;p&gt;&lt;i&gt;Six years ago I had just over 1.2 terabytes of hard drive space in my apartment. I have 3.75 terabytes hooked up to my laptop right now. (Eric Richardson)&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Six years ago today &lt;a href="http://ericrichardson.com/2006/04/1688-counting-drives"&gt;I added up all the hard drives in my apartment and got ~1,210 gigabytes&lt;/a&gt;. The largest single drive was 250 gigabytes.&lt;/p&gt;

&lt;p&gt;Today I have a two terabyte drive that I use for backups, and 750 gigabytes inside my laptop. Another terabyte drive (the one pictured) is sitting on the desk, but not being used for anything in particular.&lt;/p&gt;

&lt;p&gt;I still marvel at how cheap storage has gotten, and how quick it has gotten there.&lt;/p&gt;
</description>
  <pubDate>Wed, 18 Apr 2012 18:58:53 -0700</pubDate>
</item>
<item>
  <title>A Return to Reading</title>
  <guid>http://ericrichardson.com/2012/04/1792-a-return-to-reading</guid>
  <link>http://ericrichardson.com/2012/04/1792-a-return-to-reading</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>    &lt;img src="http://ericrichardson.com/ah/i/a98cd02e95008956a4c50fd2d55e2de4/4244-wide.jpg" width="620" height="343" alt="iPad Books" /&gt;

    &lt;p&gt;&lt;i&gt; (Eric Richardson)&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;When the new iPad came out a few weeks ago, I hopped in the car and took a drive over to the Apple store at The Grove to pick one up.  I had been intrigued but not seriously tempted by the first two models, but this time the new screen and a growing fascination with mobile devices made it something I couldn't resist.&lt;/p&gt;

&lt;p&gt;My first few weeks have produced an interesting result, though: they've made me a reader again.&lt;/p&gt;
&lt;p&gt;I've gone through four books since buying the device just a little over a month ago. I started out with Neal Stephenson's most recent release, &lt;a href="http://www.goodreads.com/book/show/10552338-reamde"&gt;Reamde&lt;/a&gt;, then circled back to some of the books that followed Orson Scott Card's &lt;a href="http://www.goodreads.com/book/show/375802.Ender_s_Game"&gt;Ender's Game&lt;/a&gt;, reading &lt;a href="http://www.goodreads.com/book/show/7967.Speaker_for_the_Dead"&gt;Speaker for the Dead&lt;/a&gt;, &lt;a href="http://www.goodreads.com/book/show/9532.Ender_s_Shadow"&gt;Ender's Shadow&lt;/a&gt; and &lt;a href="http://www.goodreads.com/book/show/9534.Shadow_of_the_Hegemon"&gt;Shadow of the Hegemon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In that time no apps have become essential parts of my life, though I will admit to spending a few hours on &lt;a href="http://firemint.com/real-racing-2-hd-home/"&gt;Real Racing 2 HD&lt;/a&gt; (and have spent a few hours more than I will admit).  I think the iPad makes an amazing web browser, and have been thoroughly impressed with the battery life.&lt;/p&gt;

&lt;p&gt;Above all, though, I've just loved having a device that I can carry to catch up on news, do some emails, and sneak a few pages from a book every time I've got an extra minute.  I've started carrying it instead of my laptop on my commute, which means that I can grab a few pages while waiting for the train and then a chapter more as I'm on the Gold Line.  Sitting in Starbucks before I head into the office it's web and email, then maybe a few more pages at lunch if I'm headed off on my own.&lt;/p&gt;

&lt;p&gt;I don't doubt that eventually other apps will find their way into my day-to-day, and I have a few ideas for ones that I could write to scratch some of my own itches, but in the meantime I'm enjoying this new return to books.  Next up: Don Delillo's &lt;a href="http://www.goodreads.com/book/show/11761.Underworld"&gt;Underworld&lt;/a&gt;, a book that's been sitting on my shelf for the last few years.  Here's to hoping this time I'll go ahead and read it through.&lt;/p&gt;
</description>
  <pubDate>Sun, 15 Apr 2012 10:41:20 -0700</pubDate>
</item>
<item>
  <title>Making Django and Rails Play Nice, Part 4: Nginx Conditionals and Passenger</title>
  <guid>http://ericrichardson.com/2012/04/1791-making-django-and-rails-play-nice-part-4</guid>
  <link>http://ericrichardson.com/2012/04/1791-making-django-and-rails-play-nice-part-4</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>&lt;p&gt;I got distracted and never managed to post the last piece of my look at making Django and Rails play nice together &lt;a href="http://www.scpr.org/beta"&gt;for KPCC's new beta website&lt;/a&gt;.  Part one &lt;a href="http://ericrichardson.com/2012/03/1784-making-rails-and-django-play-nice-with-the"&gt;looked at mapping generic relationships with MySQL views&lt;/a&gt;, part two at &lt;a href="http://ericrichardson.com/2012/03/1786-making-django-and-rails-play-nice-part-2"&gt;building interoperable sessions&lt;/a&gt; and part three at &lt;a href="http://ericrichardson.com/2012/03/1787-making-django-and-rails-play-nice-part-3"&gt;creating an interwoven caching model&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you've got all those pieces in place and have both applications happily running off the same data, though, you still need a way to route incoming requests to one or the other.  That could be something that you handle in logic on the load balancer, but our setup instead left this as something to solve as the request came into the web server.  Turns out, though, &lt;a href="http://nginx.org/"&gt;nginx&lt;/a&gt; made it all quite easy.&lt;/p&gt;
&lt;h2&gt;The Requirements&lt;/h2&gt;

&lt;p&gt;In order to declare our deployment a success, we needed the ability to gradually roll features and users from the existing Django site to the new Ruby on Rails frontend.&lt;/p&gt;

&lt;p&gt;Some paths needed to be conditional based on a beta cookie, while others needed to only point to the Django site to pick up things that we hadn't yet implemented in Rails.  Still others needed to always point to Rails, to allow ground-up development (such as [the &lt;a href="http://www.scpr.org/video/"&gt;new videos section&lt;/a&gt;) to exist only on the new site regardless of cookie status.&lt;/p&gt;

&lt;h2&gt;Nginx to the rescue!&lt;/h2&gt;

&lt;p&gt;It turns out that those requirements are exactly the sort of thing nginx is good at handling.  While "www.scpr.org" is defined in a "server" block in the nginx config, deeper constructs such as conditionals have all the same rights to define settings related to how the request will be handled.&lt;/p&gt;

&lt;p&gt;Early in the process of testing out whether this idea would work, I deployed nginx with &lt;a href="http://modrails.com/"&gt;Passenger&lt;/a&gt; to see whether Passenger's "experimental" wsgi support might work for hosting our Django app.  It turned out to run quite well, which allowed me to know that all I needed to do in nginx was set &lt;code&gt;root&lt;/code&gt; to either the Django or Rails apps and let Passenger handle the rest.&lt;/p&gt;

&lt;h2&gt;Defining a map&lt;/h2&gt;

&lt;p&gt;nginx has a nifty &lt;code&gt;map&lt;/code&gt; construct that makes up the bulk of our conditional logic:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;map $uri $test {
    ~^/$                1;
    ~^/assets/          2;
    default             0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That takes &lt;code&gt;$uri&lt;/code&gt; and tests it against the map, putting the result in $test.  The tilde in front of the keys allows regular expressions to be used.  Our simple test here will return &lt;strong&gt;one&lt;/strong&gt; (can go either way, based on cookie status) when the user is visiting the homepage, &lt;strong&gt;two&lt;/strong&gt; (Rails-only) if they're looking for something under /assets/, and &lt;strong&gt;zero&lt;/strong&gt; (Django-only) if they're trying to get anything else.  Our production map is a lot longer, but you get the idea.&lt;/p&gt;

&lt;p&gt;Once we have that, we need to add the cookie test.  This gets a little funkier.  If &lt;code&gt;$test2&lt;/code&gt; contains the results of your cookie test, typically you would want to say something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if ( $test1 == 0 || ($test1 == 1 &amp;amp;&amp;amp; $test2 == 0) ) {
    # django
} else {
    # rails
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;nginx, though, doesn't support testing multiple variables in a conditional.  That meant we needed to combine the two:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# default to old site
set $site 0;
set $test2 "";

# possible match...  two tests are combined
if ($test = 1) {
   set $test2 A;
}

# map based on existence of a cookie
if ($cookie_scprbeta = "true") {
    # use new site
    set $test2 "${test2}B";
}

if ($test2 = "AB") {
     set $site 1;
}

if ($test = 2) {
     # always map to the new site
    set $site 1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Default to site &lt;strong&gt;zero&lt;/strong&gt;, but use site &lt;strong&gt;one&lt;/strong&gt; if either a) we have a conditional match from the map and have the cookie set or b) we have a map match that is only on Rails.&lt;/p&gt;

&lt;p&gt;From there we simply set our root based on the &lt;code&gt;$site&lt;/code&gt; value:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if ($site = 0) {
        # run old site
        root /web/django_app/public/;
        passenger_min_instances 4;
}

if ($site = 1) {
        # run the new site
        root /web/rails_app/current/public/;
        rails_env "production";
        passenger_min_instances 4;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ta-da! Seamless handoff in the same visit.&lt;/p&gt;
</description>
  <pubDate>Sat, 14 Apr 2012 09:42:01 -0700</pubDate>
</item>
<item>
  <title>Brookgreen Gardens</title>
  <guid>http://ericrichardson.com/2012/04/1790-brookgreen-gardens</guid>
  <link>http://ericrichardson.com/2012/04/1790-brookgreen-gardens</link>
  <dc:creator>Eric Richardson</dc:creator>
  <description>    &lt;img src="http://ericrichardson.com/ah/i/f7d1f0fac17d34926894d98bbfb0008f/4241-wide.jpg" width="600" height="400" alt="Brookgreen Gardens" /&gt;

    &lt;p&gt;&lt;i&gt;The sun shines on an azalea in bloom near a towering oak tree. (Eric Richardson)&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Kathy and I are in South Carolina visiting family during her Spring Break.  Just up the highway from our house at Litchfield are &lt;a href="http://www.huntingtonbeachstatepark.net/"&gt;Huntington Beach State Park&lt;/a&gt; and &lt;a href="http://www.brookgreen.org/"&gt;Brookgreen Gardens&lt;/a&gt;, a pair of properties once owned by Archer and Anna Hyatt Huntington.&lt;/p&gt;

&lt;p&gt;My family used to camp at the state park every year, so I've spent much time on that side of the road, but I can only remember once that we had ever visited Brookgreen, the sculpture gardens that the pair opened to the public in 1932. We paid a return visit this week and really enjoyed wandering around the former rice plantation.&lt;/p&gt;
&lt;p&gt;A warm spring meant that even in the first week of April, many of the Brookgreen blooms were already past their prime.&lt;/p&gt;

&lt;p&gt;Given our normal views in Los Angeles, though, all the green and color was still a sight to behold.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="http://ericrichardson.com/gallery/sets/361"&gt;see more photos over in the Photos section&lt;/a&gt;.&lt;/p&gt;
</description>
  <pubDate>Fri, 06 Apr 2012 04:58:35 -0700</pubDate>
</item>
  </channel>
</rss>

