<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>The Knut Hellan Blog</title>
	<atom:link href="http://knuthellan.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://knuthellan.com</link>
	<description>General geekyness and starting a company</description>
	<lastBuildDate>Tue, 15 Dec 2009 10:05:54 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='knuthellan.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/74eea220f959bb272d364cea71714e6e?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
		<title>The Knut Hellan Blog</title>
		<link>http://knuthellan.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://knuthellan.com/osd.xml" title="The Knut Hellan Blog" />
	<atom:link rel='hub' href='http://knuthellan.com/?pushpress=hub'/>
		<item>
		<title>CouchDB Replication Monitor</title>
		<link>http://knuthellan.com/2009/11/24/couchdb-replication-monitor/</link>
		<comments>http://knuthellan.com/2009/11/24/couchdb-replication-monitor/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 11:52:44 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[couchdb]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=247</guid>
		<description><![CDATA[CouchDB does replication, but replication needs to be set up after each server restart. This means you need to ensure that replication is restarted whenever the daemon restarts CouchDB. I have never seen replication stop working without a restart, but I prefer being safe to being sorry about replication. To be perfectly honest, I do [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=247&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>CouchDB does replication, but replication needs to be set up after each server restart. This means you need to ensure that replication is restarted whenever the daemon restarts CouchDB. I have never seen replication stop working without a restart, but I prefer being safe to being sorry about replication. To be perfectly honest, I do not trust that my replication initiation after a soft CouchDB restart works properly either so I prefer to monitor the replication and have a safety mechanism in place to restart replication if needed.</p>
<p>There are several ways to monitor replication. You could fetch the status page of all servers and restart replication on servers with an empty page, but that is a kind of brute force approach in my world. A better solution is to use the replication itself to monitor that it works. </p>
<p>Each server updates their timestamp in CouchDB and this is again replicated to the other servers. This gets us a bit of the way, but not all the way. The server you are checking might have received updates from all the other servers, but you don&#8217;t know if it&#8217;s pushed out anything to the other servers. To solve this, you can add information about the other servers to the local server as well. This will give you a matrix of server replication status.</p>
<p>For each server, you will see the timestamp replicated from the server and a list of timestamps replicated to that server. The latter often being a generation older than the former. Cron can be used to update this data. The cronjob reads all the server timestamps and updates this servers timestamp followed by a list of the other servers timestamp.</p>
<p>A mapper to get a server id to server status out of the db.<br />
<code></p>
<pre>
map: function(doc) {
  emit(doc._id, doc);
}
</pre>
<p></code></p>
<p>Our monitroing database is called server_status. The design containing the mapper is called collections and the view server_list.</p>
<p>A Ruby database checker that can run on cron.<br />
<code></p>
<pre>
require 'rubygems'
require 'couchrest'
require 'json'
require 'open-uri'

STATUS_DB = 'http://localhost:5984/server_status'
COLLECTIONS = 'collections'
SERVER_LIST = 'server_list'

hostname = ARGV[0]

status_db = CouchRest.database!(STATUS_DB)
status_view = "#{STATUS_DB}/_design/#{COLLECTIONS}/_view/#{SERVER_LIST}"

# Get the current information about this server if available
server_status = begin
  status_db.get(hostname)
rescue RestClient::ResourceNotFound
  {'_id' =&gt; hostname}
end

server_status['time'] = Time.new.to_i
# Get the current times of the other servers and update this server's
# view of them
JSON(open(status_view).read)['rows'].map do |row|
  {'server' =&gt; row['id'], 'status' =&gt; row['value']}
end.each do |status|
  unless status['server'] == hostname
    server_status['servers'][status['server']] = status['status']['time']
  end
end
status_db.save_doc(server_status)
</pre>
<p></code></p>
<p>Now you need to determine when to trigger replication restart. This can be handled in the watchdog cronjob. If the highest timestamp seen for this server at other servers is above a threshold, restart replication.</p>
<p>The final loop triggering when the age is above a threshold. The init_replication method just posts a continuous replication trigger to the db:<br />
<code></p>
<pre>
JSON(open(status_view).read)['rows'].map do |row|
  {'server' =&gt; row['id'], 'status' =&gt; row['value']}
end.each do |status|
  if server_status['time'] - status['status']['time'] &gt; THRESHOLD
    init_replication(status['server'])
  end
  unless status['server'] == hostname
    server_status['servers'][status['server']] = status['status']['time']
  end
end
</pre>
<p></code></p>
<p>Rudimentary init_replication method.<br />
<code></p>
<pre>
def init_replication(server)
  target = "http://#{server}:5984"
  databases = ['server_status']
  databases.each do |db|
    config = {
            'source' =&gt; "#{db}",
            'target' =&gt; "#{target}/#{db}",
            'continuous' =&gt; true
    }
    payload = JSON.generate(config)
    result = Net::HTTP.new('127.0.0.1', '5984').post(
      '/_replicate', payload, {'content-type' =&gt; 'text/x-json'})
    unless result.code == 200
      p "replication to #{target}/#{db} failed with #{result.code}"
    end
  end
end
</pre>
<p></code></p>
<p>We have a monitoring view of replication ages in our system. It shows the matrix of timestamps as age in seconds rather than the actual timestamp since the age is the important metric.<br />
<a href="http://knuthellan.files.wordpress.com/2009/11/server_status.jpg"><img src="http://knuthellan.files.wordpress.com/2009/11/server_status.jpg?w=300&#038;h=104" alt="Server Status" title="Server Status" width="300" height="104" class="alignnone size-medium wp-image-250" /></a></p>
<p>A bonus of this replication monitoring system is that we can access the status page from a mobil phone and get an accurate picture of the replication status. This doesn&#8217;t worry me now, but it did when we first set it up. Now it&#8217;s just a part of our general monitoring view.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/247/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/247/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/247/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/247/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/247/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/247/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/247/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/247/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/247/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/247/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=247&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/11/24/couchdb-replication-monitor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>

		<media:content url="http://knuthellan.files.wordpress.com/2009/11/server_status.jpg?w=300" medium="image">
			<media:title type="html">Server Status</media:title>
		</media:content>
	</item>
		<item>
		<title>Sincerial Launched</title>
		<link>http://knuthellan.com/2009/11/02/sincerial-launched/</link>
		<comments>http://knuthellan.com/2009/11/02/sincerial-launched/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 14:25:56 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[couchdb]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[startup]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=235</guid>
		<description><![CDATA[Since we launched Sincerial with one connected online store, fundies.no on Thursday, I feel it&#8217;s time to go through the system and the choices we made on our way to launch.
Hosting
The obvious and easy choice was Amazon Web Services (AWS) Elastic Compute Cloud (EC2). A hosting service such as EC2 allows a lot of flexibility [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=235&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Since we launched <a href="http://www.sincerial.com/">Sincerial</a> with one connected online store, <a href="http://www.fundies.no/">fundies.no</a> on Thursday, I feel it&#8217;s time to go through the system and the choices we made on our way to launch.</p>
<p><strong>Hosting</strong><br />
The obvious and easy choice was <em>Amazon Web Services (AWS) Elastic Compute Cloud (EC2)</em>. A hosting service such as <em>EC2</em> allows a lot of flexibility in server solutions including quick ramp up if the luxury problem of needing more servers occurs. Freedom to choose operating system and providing a virtual server resembling what you get from a traditional hosting services were also important for us. There were alternatives, traditional hosting services where you book physical servers would incur a larger fixed cost than we wanted and at the same time, we would have lost the flexibility. We currently fire up servers and test things in no time just to shut those servers down after the test. With a traditional hosting provider, we would need spare servers for testing or used the live servers.<em> Windows Azure</em> could have been an alternative, but it&#8217;s just a <em>.NET Windows</em> hosting environment and not flexible enough. I feel I should mention Google App Engine as well, but we didn&#8217;t really consider it since it&#8217;s too restricted and even more locked in than <em>Windows Azure</em>.</p>
<p><strong>Operating System</strong><br />
We decided to use <em>CentOS</em> for the servers. The reason for this was favorable experience with <em>Fedora</em> over the last year and <em>Ubuntu</em> getting more painful at the same time.<em> Red Hat Enterprise Linux (RHEL)</em> was a contender, but <em>CentOS</em> provides us with the part of <em>RHEL</em> that we need without all the parts that we would pay for, but not use. <em>Debian</em> would have been our choice a few years back, but the <em>Fedora</em> and <em>Ubuntu</em> experiences over the last year brought us down on the <em>Fedora</em>, <em>RHEL</em>, <em>CentOS</em> side and as mentioned, <em>CentOS</em> was the best fit among those three. <em>Windows</em> wasn&#8217;t considered. We had absolutely no need for anything <em>Windows</em> in there and remote management and configuration of <em>Linux</em> systems is so much easier while being extremely stable. The <em>Amazon Machine Image (AMI)</em> we use was created by <a href="http://www.rightscale.com/">RightScale</a>.</p>
<p><strong>Web Serving Environment</strong><br />
We chose <em>Apache</em> because that&#8217;s what we&#8217;ve used in the past and <em>Apache</em> is solid and dependable. The downside of <em>Apache</em> is that it&#8217;s a big beast that might be overkill for our need. An alternative that we looked a bit at is <em>nginx</em>, but we didn&#8217;t want to spend time on that before launch. We will however look more closely at <em>nginx</em> in the future.</p>
<p><strong>Progamming Language</strong><br />
I am a rubyist and we chose <em>Ruby</em>. The first time I tried <em>Ruby</em>, I wrote a few scripts that I would normally have written in <em>Perl</em>. These weren&#8217;t big scripts, but far from one-liners. They downloaded some content and analyzed it. Writing the scripts in <em>Ruby</em> took me a bit longer than it would have taken writing them in <em>Perl</em>, but they worked right away. In <em>Perl</em> there is always something wrong unless you have a one-liner. The strongest alternative was <em>Python</em> and between <em>Ruby</em> and <em>Python</em> it comes down to taste. The first readability I got as a Googler was in <em>Python</em> and I did write a lot of <em>Python</em>, but it still doesn&#8217;t feel right. I was very happy when I got a chance to sneak myself to a <em>Ruby</em> readability. <em>Java</em> was sort of not considered, but would have been the choice if the lightweight short time-to-market alternatives hadn&#8217;t been available. We use<em> Phusion Passenger</em> to serve a combination of pure <em>Ruby</em> racks and <em>Sinatra</em> apps in <em>Apache</em>. </p>
<p><strong>Storage</strong><br />
<em>CouchDB</em> won this one. Key value storage is what we need so relational databases are a complication that we can happily forget about. Selling points of <em>CouchDB</em> was that it was easy to get started, it has an <em>HTTP RESTful API</em> and views are written as <em>Javascript</em> map-reduce. Map reduces is well suited to our calculation needs so we get a lot more done inside the database than we would do with i.e. <em>SQL</em>. The strongest alternative was definitely <em>MongoDB</em> which is very similar to <em>CouchDB</em>, but uses a more classical query language. We also briefly looked at <em>Voldemort</em>, but our calculation need is not suited to <em>Voldemort</em>&#8217;s simple key lookup scheme. <em>SimpleDB</em> ties us to <em>Amazon</em> and <em>Hadoop</em> is a bit too heavy for our needs. We didn&#8217;t consider <em>MySQL</em>, but that would have been our choice had we needed a relational database.</p>
<p><strong>Conclusion</strong><br />
Our <em>LARC</em> stack (<em>Linux</em> <em>Apache</em>, <em>Ruby</em>, <em>CouchDB</em>) works very well for us and that combination has enabled us to develop our service very quickly with the result being an easy system to maintain. We haven&#8217;t really looked back at those choices except for a few moments after upgrading to <em>CouchDB</em> 0.10.0 and seeing that our map reduces that put a lot of work in the reducers had to be rewritten. One look at <em>MongoDB</em>&#8217;s query language stopped those regrets. As mentioned when discussing web serving environments, we do consider switching from <em>Apache</em> to <em>nginx</em>, but it&#8217;s not a high priority thing and we are happy with <em>Apache</em> and the consideration comes more from curiosity than need. As for <em>CentOS</em> and <em>EC2</em>, they just work and gets out of the way which is exactly what they should do.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/235/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/235/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/235/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/235/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/235/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/235/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/235/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/235/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/235/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/235/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=235&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/11/02/sincerial-launched/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>CouchDB on Amazon EC2 CentOS server with Sprinkle</title>
		<link>http://knuthellan.com/2009/08/31/couchdb-on-amazon-ec2-centos-server-with-sprinkle/</link>
		<comments>http://knuthellan.com/2009/08/31/couchdb-on-amazon-ec2-centos-server-with-sprinkle/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 13:18:26 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[code example]]></category>
		<category><![CDATA[couchdb]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=219</guid>
		<description><![CDATA[Read the Getting Started part of Till Klampäckel&#8217;s CouchDB on Ubuntu on AWS blog post for some general information. I see no reason to repeat those things here.
Till stresses the need for a security group opening port 80, but you should also enable ssh at port 22, otherwise it will be impossible to isntall anything. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=219&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Read the Getting Started part of Till Klampäckel&#8217;s <a href="http://till.klampaeckel.de/blog/archives/55-CouchDB-on-Ubuntu-on-AWS.html">CouchDB on Ubuntu on AWS</a> blog post for some general information. I see no reason to repeat those things here.</p>
<p>Till stresses the need for a security group opening port 80, but you should also enable ssh at port 22, otherwise it will be impossible to isntall anything. The AMI I use is rightscale&#8217;s CentOS 5.2 i386 v4.2.4. If you need a 64-bit image, that should work just as well.</p>
<p>Make sure you have Sprinkle installed on you the system you are installing from. Put this in your spinkle file and name it something reasonable. I called it couchdb.rb. If not, gem install sprinkle. Sprinkle is written in Ruby so if you don&#8217;t have Ruby, you should start by installing that.</p>
<p><code><br />
# Sprinkle provisioning and deployment for CouchDB on<br />
# an Amazon EC2 CentOS server</p>
<p>package :spidermonkey do<br />
&nbsp;&nbsp;source 'http://ftp.mozilla.org/pub/mozilla.org/js/js-1.7.0.tar.gz' do<br />
&nbsp;&nbsp;&nbsp;&nbsp;custom_dir 'js/src'<br />
&nbsp;&nbsp;&nbsp;&nbsp;custom_install "make BUILD_OPT=1 -f Makefile.ref &amp;&amp; cp *.{h,tbl} /usr/include/ &amp;&amp; cd Linux_All_OPT.OBJ &amp;&amp; cp *.h /usr/include/ &amp;&amp; mkdir -p /usr/{bin,lib}/ &amp;&amp; cp js /usr/bin/ &amp;&amp; cp libjs.so /usr/lib/"<br />
end</p>
<p>&nbsp;&nbsp;verify do<br />
&nbsp;&nbsp;&nbsp;&nbsp;has_executable 'js'<br />
&nbsp;&nbsp;&nbsp;&nbsp;has_file '/usr/include/jsapi.h'<br />
&nbsp;&nbsp;&nbsp;&nbsp;has_file '/usr/lib/libjs.so'<br />
&nbsp;&nbsp;end<br />
end</p>
<p>package :erlang_dependencies do<br />
&nbsp;&nbsp;yum %w( ncurses-devel openssl-devel)<br />
end</p>
<p>package :erlang do<br />
&nbsp;&nbsp;description 'Erlang, the programming language'<br />
&nbsp;&nbsp;source 'http://erlang.org/download/otp_src_R13B01.tar.gz'</p>
<p>&nbsp;&nbsp;verify do<br />
&nbsp;&nbsp;&nbsp;&nbsp;has_executable '/usr/local/bin/erl'<br />
&nbsp;&nbsp;end</p>
<p>&nbsp;&nbsp;requires :erlang_dependencies<br />
end</p>
<p>package :couchdb_dependencies do<br />
&nbsp;&nbsp;yum %w( curl curl-devel icu libicu-devel )<br />
end</p>
<p>#   - CouchDB 0.9.1<br />
package :couchdb, :provides =&gt; :database do<br />
&nbsp;&nbsp;description 'CouchDB'<br />
&nbsp;&nbsp;version '0.9.1'<br />
&nbsp;&nbsp;source 'http://mirrorservice.nomedia.no/apache.org/couchdb/0.9.1/apache-couchdb-0.9.1.tar.gz' do<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, 'adduser -r -d /usr/local/var/lib/couchdb -M -s /bin/bash -c "CouchDB Administrator" couchdb'<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, 'touch /usr/local/var/log/couchdb/couch.log'<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, 'chown couchdb /usr/local/var/log/couchdb/couch.log'<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, 'mkdir -p /usr/local/var/lib/couchdb'<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, 'chown couchdb /usr/local/var/lib/couchdb'<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, '/usr/local/etc/rc.d/couchdb start'<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, 'ln -s /usr/local/etc/rc.d/couchdb /etc/init.d/couchdb'<br />
&nbsp;&nbsp;&nbsp;&nbsp;post :install, 'chkconfig --add couchdb'<br />
&nbsp;&nbsp;end</p>
<p>&nbsp;&nbsp;verify do<br />
&nbsp;&nbsp;&nbsp;&nbsp;has_executable '/usr/local/bin/couchdb'<br />
&nbsp;&nbsp;end</p>
<p>&nbsp;&nbsp;requires :couchdb_dependencies<br />
&nbsp;&nbsp;requires :erlang<br />
&nbsp;&nbsp;requires :spidermonkey<br />
end</p>
<p>package :rubygems do<br />
&nbsp;&nbsp;description 'Ruby Gems Package Management System'<br />
&nbsp;&nbsp;yum 'rubygems'<br />
end</p>
<p>package :couchrest do<br />
&nbsp;&nbsp;description 'Rest API for CouchDB'<br />
&nbsp;&nbsp;version '0.33'<br />
&nbsp;&nbsp;gem 'couchrest'<br />
end</p>
<p>policy :db, :roles =&gt; :db do<br />
&nbsp;&nbsp;requires :database<br />
&nbsp;&nbsp;requires :couchrest<br />
end</p>
<p># Deployment<br />
deployment do<br />
&nbsp;&nbsp;delivery :capistrano do<br />
&nbsp;&nbsp;&nbsp;&nbsp;set :user, 'root'<br />
&nbsp;&nbsp;&nbsp;&nbsp;set :use_sudo, false<br />
&nbsp;&nbsp;&nbsp;&nbsp;set :run_method, :run</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;role :db, 'ec2-x-y-z-w.eu-west-1.compute.amazonaws.com'<br />
&nbsp;&nbsp;end</p>
<p>&nbsp;&nbsp;# source based package installer defaults<br />
&nbsp;&nbsp;source do<br />
&nbsp;&nbsp;&nbsp;&nbsp;prefix   '/usr/local'           # where all source packages will be configured to install<br />
&nbsp;&nbsp;&nbsp;&nbsp;archives '/usr/local/sources'   # where all source packages will be downloaded to<br />
&nbsp;&nbsp;&nbsp;&nbsp;builds   '/usr/local/build'     # where all source packages will be built<br />
&nbsp;&nbsp;end<br />
end<br />
</code></p>
<p>Replace <em>ec2-x-y-z-w.eu-west-1.compute.amazonaws.com</em> with the public DNS name listed on the Amazon Web Services instance view. You don&#8217;t need rubygems and couchrest unless you are going to use Ruby, but I decided to leave them since CouchRest is a nice libarary to use when talking to CouchDB from Ruby.</p>
<p>Run it in a shell with <code>sprinkle -s couchdb.rb</code>. Might be interesting to check the powder cloud like this first: <code>sprinkle -cts couchdb.rb</code>. The expected cloud looks liek this:<br />
<code><br />
--&gt; Cloud hierarchy for policy db</p>
<p>Policy db requires package database<br />
Selecting couchdb for virtual package database<br />
&nbsp;&nbsp;Package couchdb requires couchdb_dependencies<br />
&nbsp;&nbsp;Package couchdb requires erlang<br />
&nbsp;&nbsp;&nbsp;&nbsp;Package erlang requires erlang_dependencies<br />
&nbsp;&nbsp;Package couchdb requires spidermonkey</p>
<p>Policy db requires package couchrest<br />
&nbsp;&nbsp;Package couchrest requires rubygems<br />
</code></p>
<p>Set up an SSH tunnel to get the remote futonI tend to use 5994 locally to avoid conflicts with the local CouchDB. <code>ssh -L 5994:localhost:5984 root@ec2-x-y-z-w.eu-west-1.compute.amazonaws.com</code> where once again, <em>ec2-x-y-z-w.eu-west-1.compute.amazonaws.com</em> should be replaced with the public DNS name listed on the Amazon Web Services instance view. Point your browser to <em>http://localhost:5994/_utils/</em> for that familiar futon view.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/219/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/219/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/219/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/219/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/219/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/219/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/219/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/219/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/219/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/219/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=219&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/08/31/couchdb-on-amazon-ec2-centos-server-with-sprinkle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>Finding the one in an ocean of provisioning and deployment systems</title>
		<link>http://knuthellan.com/2009/08/21/finding-the-one-in-an-ocean-of-provisioning-and-deployment-systems/</link>
		<comments>http://knuthellan.com/2009/08/21/finding-the-one-in-an-ocean-of-provisioning-and-deployment-systems/#comments</comments>
		<pubDate>Fri, 21 Aug 2009 07:37:37 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[deployment]]></category>
		<category><![CDATA[provisioning]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=209</guid>
		<description><![CDATA[I currently use some shell scripts for deployment. This works well on my development server. It also works when starting to run things in a data center, but there are limitations and shortcomings. For one, my deployment scripts do not have any verification. I can add that, but then again I would be duplicating work [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=209&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>I currently use some shell scripts for deployment. This works well on my development server. It also works when starting to run things in a data center, but there are limitations and shortcomings. For one, my deployment scripts do not have any verification. I can add that, but then again I would be duplicating work that others have done well before. More important is the fact that my deployment scripts assume a prepared installation environment with all the packages and gems needed installed. I want a deployment system that also provisions the target server with all my prerequisites like Apache or nginx, Passenger Phusion, Sinatra and CouchDB. Note that our application does not use Rails, the storage is handled by CouchDB and non-UI work is handled by racks running directly in Phusion. The UI is handled by Sinatra.</p>
<p>We are looking at running our service in Amazon EC2 when we are ready to launch. As we use Fedora and Ubuntu for development, the obvious candidate distros are the same or related distros like CentOS, RHEL and Debian. If the deployment system handles package installation through an abstractions system, this system must support both yum and apt. </p>
<p><a href="http://wiki.opscode.com/display/chef/Home">Chef</a><br />
Chef is built around a chef server hosting the deployment scripts (cookbooks) and chef clients managing the worker nodes. It uses CouchDB in the background for storing information. From what I see, Chef is very powerful and looks like a nice way of handling huge clusters. The power also seems to have the side-effects that doing simple things in a smallish cluster is a lot of work. Uses <a href="http://rake.rubyforge.org/">Rake</a> underneath</p>
<p><a href="http://www.capify.org/">Capistrano</a><br />
Capistrano uses it&#8217;s own DSL in combination with Ruby. Capistrano is Rails-centric, but have instructions showing how to use it for non-Rails deployment. The deployment instructions mostly run shell scripts which makes it very flexible.</p>
<p><a href="http://rubyhitsquad.com/Vlad_the_Deployer.html">Vlad the Deployer</a><br />
Vlad seems to be an extension to <a href="http://rake.rubyforge.org/">Rake</a>. Aims to be a better Capistrano. It seems very subversion oriented. One of the features is <strong>Turnkey deployment for mongrel+apache+svn</strong>. Since we&#8217;re not using mongrel or svn and although we use apache now might switch to nginx soon, this all seems wrong.</p>
<p><a href="http://reductivelabs.com/trac/puppet/">Puppet</a><br />
Puppet is an extremely flexible and powerful provisioning system. However, as is often the case, this comes at a cost. Doing simple things like our deployment is very time consuming in Puppet. It uses it&#8217;s proprietary DSL to specify very accurately how the target environment should be after running puppet. It is capable of running in the background and syncing automatically every 30 minutes or so. The feature set is overkill in our case right now and if we need those features later I&#8217;ll be a happy man who will gladly spend time moving to puppet.</p>
<p><a href="http://github.com/crafterm/sprinkle/tree/master">Sprinkle</a><br />
Sprinkle uses Ruby directly instead of a task specific DSL. Full support of the main deployment systems is included. What puzzled me at first was that it supports Capistrano and Vlad the deployer for remote command delivery. Later I realized that Sprinkle is a provisioning system and leaves application deployment to other specialized systems. Nice separation.</p>
<p><a href="http://github.com/railsmachine/moonshine/tree/master">Moonshine</a><br />
One of requirements of Moonshine is <strong>A server running Ubuntu 8.10</strong> which effectively disqualifies it for our use. I&#8217;m sure supporting other distros is not much work, but I&#8217;m not willing to do that work at this point anyway.</p>
<p><a href="http://github.com/benschwarz/passenger-stack/tree/master">Passenger_stack</a><br />
Might seem weird to include this in the list, but we use Passenger and anything that can get us there faster is considered. This would get us apache, passenger and lots of other things we do not use like MySQL. Since I do not want to install things we don&#8217;t need and passenger_stack only works on Ubuntu (and not even Debian), it is disqualified.</p>
<p><strong>Conclusion</strong><br />
With Moonshine out due to lack of distro support and Vlad the Deployer out due to being mongrel+svn focused and puppet being too difficult, the following candidates are still contestants: Chef, Capistrano and Sprinkle.</p>
<p>Sprinkle has nice dry-run functionality allowing you to see what will happen to your remote servers before you do anything. Capistrano gets praise for easy of application deployment so the Sprinkle and Capistrano combo sounds interesting. My choice is now down to Sprinkle or Chef for the server provisioning and the winner is Sprinkle. The reason for my choice is that it is simpler and does what I currently need it to do. Migrating to Chef in the future is still an option.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/209/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/209/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/209/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/209/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/209/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/209/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/209/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/209/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/209/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/209/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=209&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/08/21/finding-the-one-in-an-ocean-of-provisioning-and-deployment-systems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>The CouchDB indexer &#8211; lightweight search engine in hours</title>
		<link>http://knuthellan.com/2009/07/09/the-couchdb-indexer-lightweight-search-engine-in-hours/</link>
		<comments>http://knuthellan.com/2009/07/09/the-couchdb-indexer-lightweight-search-engine-in-hours/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 10:55:42 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[code example]]></category>
		<category><![CDATA[couchdb]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=185</guid>
		<description><![CDATA[Have you ever been in a situation where you needed to create a reverse lookup index of some documents you had lying around?
A reverse lookup index is the kind of index used by the search engines (or Googles if you like) of this world. Creating a reverse lookup index isn&#8217;t hard, but you would normally [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=185&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Have you ever been in a situation where you needed to create a reverse lookup index of some documents you had lying around?</p>
<p>A reverse lookup index is the kind of index used by the search engines (or Googles if you like) of this world. Creating a reverse lookup index isn&#8217;t hard, but you would normally expect to spend a couple of weeks writing code to create one when needed unless you decide to use an existing indexer like lucene. Using lucene is a bit heavy if the indexing is not core to your application. If you store your documents in CouchDB, you can create an indexer writing just 4 lines of JavaScript. You should have at least one more line for safeguarding your input values, but a search engine indexer in 5 lines of JavaScript is IMHO still pretty good.</p>
<p>The prerequisite for this indexer is that the documents you want to index all have a vector field containing a document vector in the form of a hash mapping term to term weight {&lt;term0&gt; =&gt; &lt;tweight0&gt;, &lt;tterm1&gt; =&gt; &lt;tweight1&gt;, &#8230;,&lt;ttermn&gt; =&gt; &lt;tweightn&gt;}. The weight could be just the number of times a term occurs in the document or a some metric indicating how important a word is to a document relative to all possible documents. The traditional weight used in search engines is tf-idf (term frequency multiplied by inverse document frequency). Head over to <a href="http://en.wikipedia.org/wiki/Tf%E2%80%93idf">Wikipedia</a> if you want to learn more about tf-idf. Of course, if you just want to find all documents matching a query, you can ignore the weights completely.</p>
<p>If you have document vectors, you have all the input data you need to create a reverse lookup index. This is the mapper if you just want to get all documents matching a query. Note that it completely ignores the term weights: </p>
<pre><code>
function(doc) {
    if (!('vector' in doc)) return;
    var vector = doc.vector;
    for (var term in vector) {
        emit(term, doc._id);
    }
}
</code></pre>
<p>The function operates on each document in the database. The first statement is a simple safeguard ensuring that we don&#8217;t try to access vector if the document doesn&#8217;t have that property. Since CouchDB is schema free, different types of documents with different fields may be stored in the same database. If the vector property is there, we store it in a variable called vector. For each element in vector, we emit the key which is the term and the id of the document we are operating on. If you run just this mapper, you will get a list of term to single document id mappings. This is a major step forward since we now have a reverse mapping of the database. </p>
<p>To get the reverse database map into something that is quick and easy to lookup, we need a reducer. It&#8217;s purpose is to convert the list of term, document id pairs into a single term to document id list.</p>
<pre><code>
function(keys, values) {
    var docs = [];
    for (var i = 0; i &lt; values.length; ++i) {
        docs.push(values[i]);
    }
    return docs;
}
</code></pre>
<p>In this situation, we don&#8217;t care about the keys. CouchDB handles that for us. We need an array to store all the document ids. Then we iterate over all the values and push them into our array. Finally we return the array. CouchDB ensures that this is only called once for a single term ensuring we end up with a single document id list for each term.</p>
<p>This index can be used to find all documents matching a given set of terms. Note that there is not much sophistication in this method so the only rank score you can get is the number of matching terms. Adding term weights to the index will give you something to use for ranking. Change the emit line in the mapper to<br />
<code><br />
emit(term, [doc._id, vector[term]]);<br />
</code><br />
This will give you a list of document id, term weight pairs for each term instead of just the document ids.</p>
<p>That mapper is 7 lines of code, 4 lines if you don&#8217;t count the function declaration line and lines only containing curly braces. Ignoring the safe guard as well, the mapper body can be reduced to this single line by also skipping the temporary variable assignment:<br />
<code><br />
for (var term in doc.vector) emit(term, [doc._id, doc.vector[term]]);<br />
</code><br />
In the same manner, the reduce function may be reduced to a body of just 3 lines of code<br />
<code><br />
var docs = [];<br />
for (var i = 0; i &lt; values.length; ++i) docs.push(values[i]);<br />
return docs;<br />
</code><br />
That&#8217;s the power and beauty of CouchDB map reduce. You can write a search engine indexer in 4 lines of JavaScript. Granted, you need to create vectors of your documents in advance, but that&#8217;s just a matter of parsing a text string and splitting on whitespace and/or punctuation into an array and reducing the term array into a hash of &lt;term&gt; =&gt; &lt;weight&gt; pairs. Sure, you can do this with a map reduce as well, but that might be overkill since you will only be operating on a single document at a time.</p>
<p>One last important point is that while Futon, the CouchDB browser client will show the expected results, you have to explicitly tell CouchDB to group the result if you want to use this in your application. My database is called <code>pages</code>, the design is called <code>demos</code> and the view <code>index</code> making the output of the map reduce available as json at<br />
<code>http://localhost:5984/pages/_design/demos/_view/index?group=true</code><br />
Thanks to <a href="http://twitter.com/jchris">J. Chris Anderson</a> for clarifying and pointing out the grouping query usage.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/185/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=185&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/07/09/the-couchdb-indexer-lightweight-search-engine-in-hours/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>Meet the people</title>
		<link>http://knuthellan.com/2009/06/29/meet-the-people/</link>
		<comments>http://knuthellan.com/2009/06/29/meet-the-people/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 14:31:23 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[startup]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=161</guid>
		<description><![CDATA[In the beforetime, before I started working in search engine companies, I had some direct customer relations. I didn&#8217;t think much about it back then, but I have great memories of the experiences I got from dealing with customers. I tend to be rated extrovert on personality tests, but if that&#8217;s true, I&#8217;m a conditional [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=161&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>In the beforetime, before I started working in search engine companies, I had some direct customer relations. I didn&#8217;t think much about it back then, but I have great memories of the experiences I got from dealing with customers. I tend to be rated extrovert on personality tests, but if that&#8217;s true, I&#8217;m a conditional extrovert. Granted, I enjoy spending time with friends and socializing, but I&#8217;m also quite fond of sitting by myself in front of a keyboard. What I remember from that time was that I was always nervous before meeting the customers, but when we were face to face, everything was fine and I enjoyed their company as well as the learning experience.</p>
<p>During the last years, direct customer relations haven&#8217;t been that much of an issue. There was a time while I was working for FAST Search &amp; Transfer that we had fairly regular conference calls with one particular customer. They had valuable deep web content that was unavailable to crawlers. We did a joint project between the two companies to make their content available to our web search index. This whole experience did not have much in common with a traditional customer-provider relationship. I have held training sessions and presentations internally over the years, but while I might be a little nervous before presenting to lots of people, it&#8217;s mostly just business as usual. In other words, no customer fronting experiences for me in almost 10 years.</p>
<p>Now that I&#8217;m bootstrapping a company, I have started talking to (potential) customers again. I am lucky enough to have a friend as pilot customer so it&#8217;s once again not a traditional customer-provider relationship. He is also talking to other potential customers through his network and gathers feedback. Getting that feedback and seeing that it mostly reflect what we expect is great, but I always learn new things whenever I talk to him. These things might seem obvious or minor to him, but it is important for us either for confirming our assumptions or showing that our assumptions are wrong.</p>
<p>As I mentioned in the beginning, I&#8217;m a conditional extrovert, but meeting customers again makes me realize that I have missed this. Presenting our plans to governmental institutions before applying for a grant and other potential future investors is fun. I&#8217;ll be the first to admit that I may be nervous before such presentations, but when the first page of the presentation is up and I start talking it&#8217;s more of a rush than anything else. Answering questions from customers and investors is fun too because I believe we are on to something. Moreover, we are talking about something that no one has told me to do. I am the one airing my thoughts to others and they react positively. It&#8217;s a great way of building confidence in yourself and what you are doing.</p>
<p>I remember another thing from the beforetime. A salesman in the company I worked for and I were working together at a trade fair when some potential future customers that he had briefly been in touch with before showed up. He talked them through the things we could do for them and generally spent some time discussing various alternatives with them. When they had left, he almost celebrated and said aloud to himself &#8220;I&#8217;m so good at this.&#8221; and he was. He was extremely good at what he was doing. For me, this was a great learning experience. I observed him during this seance and others and learned (I hope), but most of all I realized how big an energy rush you can get from good talks with customers. </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/161/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=161&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/06/29/meet-the-people/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>Lifestyle design</title>
		<link>http://knuthellan.com/2009/06/19/lifestyle-design/</link>
		<comments>http://knuthellan.com/2009/06/19/lifestyle-design/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 11:43:15 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[startup]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=142</guid>
		<description><![CDATA[I read Jeremy Lattimore&#8217;s blog post about lifestyle design on Startup Student the other day and it got me thinking. Sure, I have thought about the concept several times since I decided to found a company rather than taking a regular job, but reading that blog post made me more conscious about my decisions. Furthermore, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=142&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>I read <a href="http://startupstudent.com/2009/06/16/why-am-i-doing-this/">Jeremy Lattimore&#8217;s blog post about lifestyle design</a> on Startup Student the other day and it got me thinking. Sure, I have thought about the concept several times since I decided to found a company rather than taking a regular job, but reading that blog post made me more conscious about my decisions. Furthermore, it forced me to reflect on how starting a company is lifestyle design in many ways.</p>
<p>The <a href="http://www.davidrisley.com/2009/06/17/lifestyle-design/">stereotypical lifestyle design as described in David Risley&#8217;s example</a> is to come up with a fairly cheap, easy to sell product. While I&#8217;ve not gotten around to reading <a href="http://www.timferriss.com/">Tim Ferriss</a>&#8216; <a href="http://www.fourhourworkweek.com/">4-Hour Workweek</a> (it&#8217;s in my house in paper form, honestly), I think this is the primary example Tim uses in his defining book about lifestyle design as well. This approach is somewhat different from the approach used by Jeremy Lattimore, but the final goal is basically the same.</p>
<p>In my case, I had something that I desperately wanted to do. There is a theme that has been at the core of some things I have enjoyed working on over the last few years and I believe there are lots of business opportunities centered around this technology. When I set out, I did not want to start this all by myself. I wanted to have one to three other people heavily involved both to discuss plans and to verify that the idea was good. The one I wanted the most since I knew he also has an interested in the core technology was very eager to be involved and things started to happen. Now, we have a business development company involved, a pilot customer and leads to the next batch of customers as well as a possible lead to a large number of long term customers.</p>
<p>So, I&#8217;m starting a company and that does not exactly sound like lifestyle design. Starting a company means working long hours, with little or no pay and making things difficult for oneself. This is in many ways true, generating revenue doesn&#8217;t happen over night and the bigger your goals are, the longer it takes for that revenue stream to turn into a profit. I am willing to work long hours and I expect to have to live off my savings for a long time and get some funding to hire more people in the not too distant future, but&#8230; In the current situation, I work from home and I work when I want to rather than when some early bird has decided that I should work. I don&#8217;t feel bad about taking breaks during the day and I don&#8217;t force myself to pretend to work when I don&#8217;t think I will get anything done because I&#8217;m either too tired or my mind is preoccupied with something else. This does not mean that I&#8217;m slacking, I&#8217;m just focusing on output rather than time.</p>
<p>Looking back at my weekly sprints, I see that I mostly finish ahead of time and only once did I fail to complete my sprint in time. I actually worked longer hours during the failed sprint than otherwise since it was much harder than expected. Now, as I write this blog post, I am way ahead of the original schedule and we should have no technical problems meeting our first major milestone, first customer live.</p>
<p>Is this lifestyle design? To me, it is. I&#8217;ve been coding since I was 11 or so and I started because it was interesting and fun. The service we are developing is something I would like to use myself and I&#8217;m having fun developing it. While I don&#8217;t have a steady stream of money flowing into the bank at the moment, I believe that this service will make money and generate a profit at some point and while getting there, I am having fun coding and writing blog posts. I expected to have fun along the way when I decided to try out the startup life and I feel in control. I think this is very much in tune with <a href="http://startupstudent.com/2009/06/16/why-am-i-doing-this/">Jeremy Lattimore&#8217;s</a> lifestyle design thoughts.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/142/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=142&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/06/19/lifestyle-design/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>The week of June 15 in links</title>
		<link>http://knuthellan.com/2009/06/19/130/</link>
		<comments>http://knuthellan.com/2009/06/19/130/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 09:40:25 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[links]]></category>
		<category><![CDATA[digest]]></category>

		<guid isPermaLink="false">http://knuthellan.com/?p=130</guid>
		<description><![CDATA[Last weeks links. Lots of RTs as usual. The span of links goes from zombie music all the way to cooking, but most of the links are to more classic geek stuff:

I wonder how much time I will spend on getting Kindle stuff to work on my netbook. My Asus eee 1000he is my current [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=130&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Last weeks links. Lots of RTs as usual. The span of links goes from zombie music all the way to cooking, but most of the links are to more classic geek stuff:</p>
<ul>
<li>I wonder how much time I will spend on getting <a href="http://www.amazon.com/gp/help/customer/display.html?ie=UTF8&amp;nodeId=200203720">Kindle</a> stuff to work on my netbook. My Asus eee 1000he is my current book reader and I prefer it to paper books. My ebook reader app of choice was <a href="http://www.ereader.com/">eReader</a>, but now they&#8217;re refusing to sell me books since I live in Norway so I need to find alternatives. Luckily, I still have a stack of unread books in eReader, but they will run out eventually and then I need to find another source of books. A Kindle app could be the best solution.</li>
<li>RT @phusion_nl <a href="http://blog.phusion.nl/2009/06/17/phusion-passenger-223-released-bug-fix-edition/">Phusion Passenger 2.2.3</a> &#8220;Bug Fix Edition&#8221; released. Passenger makes my set of Racks including Sinatra run in a web server environment (Apache) that I trust. I will also test Passenger with nginx, but that&#8217;s a bit down on my todo list.</li>
<li>RT @startupstudent: New blog post: <a href="http://startupstudent.com/2009/06/16/why-am-i-doing-this/">Why am I doing this?</a>. I commented on the blog post, but I will actually publish my own take on startup life vs lifestyle design inspired by this post later today.</li>
<li>RT @timbury: RT @StevoMoviemaker RT @MrMarketingMan: NC &#8211; loved this. <a href="http://news.cnet.com/8301-17938_105-10265102-1.html">Twitter from your Commodore 64</a>. How cool is that? Both my wife and I still have C64s and last we checked, they worked. Back in the 80s, making the breadbox do things it wasn&#8217;t meant for was cool, but we mostly focused on sound and graphics. Any network connection would&#8217;ve been a dead slow modem</li>
<li>RT @ruby_news <a href="http://effectif.com/articles/testing-rails-with-rack-test">Testing Rails with Rack::Test</a>. I&#8217;m not using Rails, but I use Rack and Sinatra. If you&#8217;re developing Rack applications (no matter which framework) and not using <a href="http://github.com/brynary/rack-test/tree/master">Rack::Test</a> you should either start doing so now or let me know which testing framework is even better.</li>
<li>Another great recipe from Just Bento is the <a href="http://justbento.com/handbook/recipe-collection-mains/tuna-tofu-miso-mini-burgers">tuna tofu miso burger</a> recipe. I haven&#8217;t tried this one, but I will as it looks and sounds delicious.</li>
<li>RT @civis: <a href="http://justbento.com/handbook/recipe-collection-mains/1-egg-tamagoyaki-japanese-omelette">1 egg tamagoyaki (Japanese omelette)</a> | Just Bento &#8211; I made one of these for lunch this week and loved it. Dead easy to make when following this recipe and low cal as well.</li>
<li>RT @ruby_news:  <a href="http://www.igvita.com/2009/06/13/profiling-ruby-with-googles-perftools/">Profiling Ruby With Google’s Perftools</a> &#8211; I know I&#8217;ll be using this in the coming month</li>
<li>My favorite for the summer hit of 2010 &#8211; <a href="http://mailorderzombie.libsyn.com/index.php?post_id=489965">Shamblin&#8217; Back</a> by Brother D of <a href="http://mailorderzombie.libsyn.com/">Mail Order Zombie</a></li>
<li>RT @atveit: RT @abiody <a href="http://abiody.com/index.php/2009/06/abiody-ready-for-business-from-july-1st/">Abiody ready for (cloud) business from July 1st</a> &#8211; Interesting cloud oriented startup.</li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/130/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/130/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/130/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=130&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/06/19/130/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>A fistful of links</title>
		<link>http://knuthellan.com/2009/06/10/a-fistful-of-links/</link>
		<comments>http://knuthellan.com/2009/06/10/a-fistful-of-links/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 13:08:34 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://knuthellan.wordpress.com/?p=122</guid>
		<description><![CDATA[Here&#8217;s a list of links I tweeted over the last week or so (as requested by @dmpetersson). I considered shamelessly removing the RT info, but came to my senses and carried them over. Clearly shows that the majority of my links are retweets, but then again more people might discover the interesting people who originally [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=122&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a list of links I tweeted over the last week or so (as requested by @dmpetersson). I considered shamelessly removing the RT info, but came to my senses and carried them over. Clearly shows that the majority of my links are retweets, but then again more people might discover the interesting people who originally tweeted the links and follow them. I will start posting these digests weekly going forwards.</p>
<ul>
<li><a href="http://www.engadget.com/2009/06/09/fedora-11-packs-a-next-gen-file-system-faster-boot-times-all-t/">Fedora 11 is here</a> &#8211; looks like a nice upgrade from Fedora 10 and remains a good alternative to Ubuntu.</li>
<li><a href="http://jan.prima.de/~jan/plok/archives/175-Benchmarks-You-are-Doing-it-Wrong.html">Benchmarks: You are Doing it Wrong</a> &#8211; interesting read about benchmarking web applications</li>
<li>RT @Venture_Capital <a href="http://dealbook.blogs.nytimes.com/2009/06/09/do-young-venture-capitalists-have-an-edge/">Do Young Venture Capitalists Have an Edge?</a> &#8211; Experience is good, but so is openness to new ideas</li>
<li>RT @DanekS <a href="http://www.getfreepublicitynow.com/?p=310">How to write a tech press release</a> &#8211; don&#8217;t show off. Journalists and editors may not understand geek</li>
<li>RT @tferriss: Find out which interests Google associates with your cookie &#8211; <a href="http://www.google.com/ads/preferences/">who does Google think you are?</a></li>
<li>RT @ruby_news: <a href="http://www.infoq.com/news/2009/05/rack10">Rack 1.0</a> Released </li>
<li>RT @tferriss: <a href="http://www.usabilitypost.com/2008/09/29/a-guide-to-choosing-colors-for-your-brand/">How to choose colors for your brand</a> &#8211; great samples:  via @gmc</li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/122/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=122&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/06/10/a-fistful-of-links/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
		<item>
		<title>OAuth and the 4 hour work day</title>
		<link>http://knuthellan.com/2009/06/05/oauth-and-the-4-hour-work-day/</link>
		<comments>http://knuthellan.com/2009/06/05/oauth-and-the-4-hour-work-day/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 08:30:51 +0000</pubDate>
		<dc:creator>knuthellan</dc:creator>
				<category><![CDATA[authorization]]></category>

		<guid isPermaLink="false">http://knuthellan.wordpress.com/?p=92</guid>
		<description><![CDATA[I must admit that I&#8217;m quite fond of the 4 hour work day. With that I don&#8217;t mean working excatly 4 hours per day, but the principle as explained by Scott Young. Come to think of it, the 4 hour part isn&#8217;t important at all, it&#8217;s the daily todo lists I like. I understand the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=92&subd=knuthellan&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>I must admit that I&#8217;m quite fond of the 4 hour work day. With that I don&#8217;t mean working excatly 4 hours per day, but the principle as explained by <a href="http://thinksimplenow.com/productivity/the-4-hour-workday/">Scott Young</a>. Come to think of it, the 4 hour part isn&#8217;t important at all, it&#8217;s the daily todo lists I like. I understand the desire to limit the actual time working if you hate what you do, but I am excited about my work and rather enjoy spending time on it.</p>
<p>On a given day, I start out making a list of the things I want to achieve on that day. If I get through my todo lists correctly every day in a week, I will successfully complete my (scrum) sprint. Of course, since I&#8217;m developing from scratch, estimation is much easier than it would be if I were surrounded by legacy systems. Interestingly, I normally overestimate and end up completing tasks much faster than expected. Maybe the standard software developer estimation factor (multiply the estimate by 3.14) is a result of reasonable estimates meeting legacy systems.</p>
<p>This was meant to be about OAuth and not estimation I suppose. The <a href="http://oauth.net/">spec</a> is a bit too much to go into here. OAuth is: </p>
<blockquote><p>An <strong>open protocol</strong> to allow <strong>secure API authorization</strong> in a <strong>simple</strong> and <strong>standard</strong> method from desktop and web applications.</p></blockquote>
<p>Letting OAuth speak for itself rather than trying to explain it with my own words felt good.</p>
<p>When needing to support OAuth authentication on our servers, I started out developing a consumer in Ruby as a Rack application. To test it, I used <a href="http://agree2.com/">Agree2</a> since there is an excellent <a href="http://stakeventures.com/articles/2008/02/23/developing-oauth-clients-in-ruby">tutorial</a> using <a href="http://agree2.com/">Agree2</a> as an example service. Following the tutorial, I had a working consumer faster than estimated. The next step was to get my own OAuth Server running as a Rack application. Now this was a gauntlet run. First, I needed to get the communication sequence right. That wasn&#8217;t too hard, but I missed my estimates slightly. Next up was to start making things secure by verifying and signing messages. At this point things slowed down substantially. I had to read parts of the spec again and again while staring at my code. I eventually got my Rack based consumer to authorize with my Rack based server. All estimates were off, but at least it was working.</p>
<p>I know that our customers will use various systems to talk to our service. We expect to develop plugins for our service in their systems ourselves, and that means we should do the OAuth support as well. Our pilot customer has a PHP based system so the next step was to make the plugin for that system use OAuth. This was also the time I implemented verification of signed requests on the server side. I&#8217;ll cheat again with the description of the signature base string which is the basis for the signature:</p>
<blockquote><p>The Signature Base String is a consistent reproducible concatenation of the request elements into a single string. The string is used as an input in hashing or signing algorithms. The HMAC-SHA1 signature method provides both a standard and an example of using the Signature Base String with a signing algorithm to generate signatures. All the request parameters MUST be encoded as described in Parameter Encoding (Parameter Encoding) prior to constructing the Signature Base String.</p></blockquote>
<p>The OAuth spec is pretty specific on most things, but there are a few things that can cause problems when you start signing messages. Getting HTTP Get requests to work when signed was pretty straightforward. HTTP Post was worse. First of all, I am used to posting JSONs directly without thinking key, value pairs. This has interesting side-effects when the PHP library treats the JSON as a key and sorts it before the HTTP authentication parameters in the signature base string while the Ruby library sorts it after the HTTP authentication parameters. The <a href="http://code.google.com/p/oauth-php/wiki/ConsumerHowTo">PHP Consumer Tutorial</a> I followed suggested you just convert your payload to a simple array. Surprisingly my JSON ended up not being included in the signature base string generated by the PHP library at all. The Ruby library however included it which is of course the right thing to do. The solution was to use an associative array with key &#8216;payload&#8217;. This was included in the signature base string by both the PHP and Ruby libraries. I had full functionality.</p>
<p>Next up is the handling of space in URLs. PHP is fond of encoding spaces as plus signs: <em>&#8220;Alfa&nbsp;Romeo&#8221;</em> -&gt; <em>&#8220;Alfa+Romeo&#8221;</em> while Ruby tends to use the arguably more correct %20 encoding: <em>&#8220;Alfa&nbsp;Romeo&#8221;</em> -&gt; <em>&#8220;Alfa%20Romeo&#8221;</em>. To my surprise, I never had any problems with this. I did have URL encoding issues, but they weren&#8217;t as simple as this. </p>
<p>After deploying my Rack applications to Passenger Phusion and Apache, the Ruby library started complaining about <em>&#8220;http://localhost/Some&nbsp;Name/something&#8221;</em> not being a proper URI. URI(is not URI?) is what it said. Now it was easy to see that the space was the problem, but not how it became a problem. After scanning through the library, I found that it uses the parse method of the standard Ruby uri module to verify correctness of URLs. Furthermore I found that it uses <code>env['PATH_INFO']</code> to generate the <em>&#8220;/Some&nbsp;Name/something&#8221;</em> part of this URL. I tried to use <code>CGI.escape</code> on this value, but that escaped a bit too much. The sad, but working solution was to substitute <em>&#8216;&nbsp;&#8217;</em> with <em>&#8216;%20&#8242;</em> like this: <code>request.path_info = env['PATH_INFO'].gsub('&nbsp;', '%20')</code></p>
<p>Now everything works perfectly with my PHP consumer. A few questions remain. The first and most important question is whether I trust these libraries after struggling like this. The easy answer is that I do. There are no security issues, just some pain and bloodshed needed to get them to work. The next question is what happens when we need to support consumers in <a href="http://en.wikipedia.org/wiki/ColdFusion_Markup_Language">ColdFusion Markup Language</a>, <a href="http://en.wikipedia.org/wiki/Active_Server_Pages">ASP</a> and other web scripting languages. I don&#8217;t know the answer to that. I guess the experience working with PHP will be helpful, but I also expect other pitfalls to show up. Time will tell.</p>
<p>Now what has this OAuth stuff got to do with the estimation and <a href="http://thinksimplenow.com/productivity/the-4-hour-workday/">4 hour work day</a> principle I started with? Actually a lot. While OAuth  isn&#8217;t exactly a legacy system, the added complexity was comparable. Getting the handshaking to work properly was straightforward and implementation was similar to what I expected and this is the part I actually estimated. When I got to the cross language part and request signing, I encountered a string of unexpected hurdles much like you would see developing in a legacy system. If I were to follow the <a href="http://thinksimplenow.com/productivity/the-4-hour-workday/">4 hour work day</a> principle mindlessly, I would have had to do a couple of all-nighters in a row. I do believe my estimation was off by a factor of around 3.14 on average. </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/knuthellan.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/knuthellan.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/knuthellan.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/knuthellan.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/knuthellan.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/knuthellan.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/knuthellan.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/knuthellan.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/knuthellan.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/knuthellan.wordpress.com/92/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=knuthellan.com&blog=6371883&post=92&subd=knuthellan&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://knuthellan.com/2009/06/05/oauth-and-the-4-hour-work-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">knuthellan</media:title>
		</media:content>
	</item>
	</channel>
</rss>