<?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>Andrew Wilkinson</title>
	<atom:link href="http://andrewwilkinson.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://andrewwilkinson.wordpress.com</link>
	<description>Random Ramblings on Programming</description>
	<lastBuildDate>Wed, 25 Jan 2012 09:22:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='andrewwilkinson.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Andrew Wilkinson</title>
		<link>http://andrewwilkinson.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://andrewwilkinson.wordpress.com/osd.xml" title="Andrew Wilkinson" />
	<atom:link rel='hub' href='http://andrewwilkinson.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Integrating Python and Javascript with PyV8</title>
		<link>http://andrewwilkinson.wordpress.com/2012/01/23/integrating-python-and-javascript-with-pyv8/</link>
		<comments>http://andrewwilkinson.wordpress.com/2012/01/23/integrating-python-and-javascript-with-pyv8/#comments</comments>
		<pubDate>Mon, 23 Jan 2012 14:15:51 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[pyv8]]></category>
		<category><![CDATA[v8]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=661</guid>
		<description><![CDATA[A hobby project of mine would be made much easier if I could run the same code on the server as I run in the web browser. Projects like Node.js have made Javascript on the server a more realistic prospect, but I don&#8217;t want to give up on Python and Django, my preferred web development [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=661&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/scania/2869106546/"><img style="float:right;border:0;" src="http://farm4.staticflickr.com/3153/2869106546_662f446a43_m.jpg" alt="Scania 500/560/580/620 hp 16-litre Euro 3/4/5 V8 engine" /></a>A hobby project of mine would be made much easier if I could run the same code on the server as I run in the web browser. Projects like <a href="http://nodejs.org/">Node.js</a> have made Javascript on the server a more realistic prospect, but I don&#8217;t want to give up on <a href="http://www.python.org/">Python</a> and <a href="http://www.djangoproject.com/">Django</a>, my preferred web development tools.</p>
<p>The obvious solution to this problem is to embed Javascript in Python and to call the key bits of Javascript code from Python. There are two major Javascript interpreters, <a href="https://developer.mozilla.org/en/SpiderMonkey">Mozilla&#8217;s SpiderMonkey</a> and <a href="http://code.google.com/p/v8/">Google&#8217;s V8</a>. Unfortunately the <a href="http://code.google.com/p/python-spidermonkey/">python-spidermonkey</a> project is dead and there&#8217;s no way of telling if it works with later version of SpiderMonkey. The <a href="http://code.google.com/p/pyv8/updates/list">PyV8</a> project by contrast is still undergoing active development.</p>
<p>Although PyV8 has a wiki page entitled <a href="http://code.google.com/p/pyv8/wiki/HowToBuild">How To Build</a> it&#8217;s not simple to get the project built. They recommend using prebuilt packages, but there are none for recent version of Ubuntu. In this post I&#8217;ll describe how to build it on Ubuntu 11.11 and give a simple example of it in action.</p>
<p>The first step is make sure you have the appropriate packages. There may be others that are required and not part of the default install, but there are what I had to install.</p>
<p><pre class="brush: bash;">
sudo aptitude install scons libboost-python-dev
</pre></p>
<p>Next you need to checkout both the V8 and PyV8 projects using the commands below.</p>
<p><pre class="brush: bash;">
svn checkout http://v8.googlecode.com/svn/trunk/ v8
svn checkout http://pyv8.googlecode.com/svn/trunk/ pyv8
</pre></p>
<p>The key step before building PyV8 is to set the <tt>V8_HOME</tt> environment variable to the directory where you checked out the V8 code. This allows PyV8 to patch V8 and build it as a static library rather than the default dynamic library. Once you&#8217;ve set that you can use the standard Python <tt>setup.py</tt> commands to build and install the library.</p>
<p><pre class="brush: bash;">
cd v8
export PyV8=`pwd`
cd ../pyv8
python setup.py build
sudo python setup.py install
</pre></p>
<p>In future I&#8217;ll write more detailed posts about how to use PyV8, but let&#8217;s start with a simple example. <a href="http://mustache.github.com/">Mustache</a> is a simple template language that is ideal when you want to create templates in Javascript. There&#8217;s actually a <a href="https://github.com/defunkt/pystache">Python implementation</a> of Mustache, but let&#8217;s pretend that it doesn&#8217;t exist.</p>
<p>To start import the <tt>PyV8</tt> library and create a <tt>JSContext</tt> object. These are equivalent to sub-interpreters so you have several instance of your Javascript code running at once.</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; import PyV8
&gt;&gt;&gt; ctxt = PyV8.JSContext()
</pre></p>
<p>Before you can run any Javascript code you need <tt>enter()</tt> the context. You should also <tt>exit()</tt> it when you are complete. <tt>JSContext</tt> objects can be used with <tt>with</tt> statements to automate this, but for a console session it&#8217;s simplest to call the method explicitly. Next we call <tt>eval()</tt> to run our Javascript code, first by reading in the Mustache library and then to set up our template as a variable.</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; ctxt.enter()
&gt;&gt;&gt; ctxt.eval(open(&quot;mustache.js&quot;).read())
&gt;&gt;&gt; ctxt.eval(&quot;var template = 'Javascript in Python is {{ opinion }}';&quot;)
</pre></p>
<p>The final stage is to render the template by dynamically created some Javascript code. The results of the expressions are returned as Python objects, so here <tt>rendered</tt> contains a Python string.</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; import random
&gt;&gt;&gt; opinion = random.choice([&quot;cool&quot;, &quot;great&quot;, &quot;nice&quot;, &quot;insane&quot;])
&gt;&gt;&gt; rendered = ctxt.eval(&quot;Mustache.to_html(template, { opinion: '%s' })&quot; % (opinion, ))
&gt;&gt;&gt; print rendered
Javascript in Python is nice
</pre></p>
<p>There&#8217;s much more to PyV8 than I&#8217;ve described in this post, including calling Python code from Javascript but unfortunately the V8 and PyV8 documentation is a bit lacking. I will post some more of my discoveries in future posts.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/scania/2869106546/">Scania 500/560/580/620 hp 16-litre Euro 3/4/5 V8 engine</a> by <a href="http://www.flickr.com/photos/scania/">Scania Group</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/661/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/661/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/661/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/661/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/661/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/661/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/661/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/661/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/661/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/661/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/661/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/661/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/661/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/661/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=661&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2012/01/23/integrating-python-and-javascript-with-pyv8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm4.staticflickr.com/3153/2869106546_662f446a43_m.jpg" medium="image">
			<media:title type="html">Scania 500/560/580/620 hp 16-litre Euro 3/4/5 V8 engine</media:title>
		</media:content>
	</item>
		<item>
		<title>Back Garden Weather in CouchDB (Part 4)</title>
		<link>http://andrewwilkinson.wordpress.com/2012/01/20/back-garden-weather-in-couchdb-part-4/</link>
		<comments>http://andrewwilkinson.wordpress.com/2012/01/20/back-garden-weather-in-couchdb-part-4/#comments</comments>
		<pubDate>Fri, 20 Jan 2012 14:15:19 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[couchdb]]></category>
		<category><![CDATA[weather]]></category>
		<category><![CDATA[couchapp]]></category>
		<category><![CDATA[mustache]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=652</guid>
		<description><![CDATA[In this series of posts I&#8217;m describing how I created a CouchDB CouchApp to display the weather data collected by the weather station in my back garden. In the previous post I showed you how to display a single day&#8217;s weather data. In this post we will look at processing the data to display it [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=652&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/13422316@N00/243295768/"><img style="float:right;border:0;" src="http://farm1.staticflickr.com/85/243295768_5f556ef303_m.jpg" alt="Weather front" /></a>In this series of posts I&#8217;m describing how I created a <a href="http://www.couchdb.org">CouchDB</a> <a href="http://couchapp.org/page/index">CouchApp</a> to <a href="http://www.welwynweather.co.uk">display the weather data</a> collected by the weather station in my back garden. In the <a href="http://andrewwilkinson.wordpress.com/2012/01/12/back-garden-weather-in-couchdb-part-3/">previous post</a> I showed you how to display a single day&#8217;s weather data. In this post we will look at processing the data to display it by month.</p>
<p>The data my weather station collects consists of a record every five minutes. This means that a 31 day month will consist of 8,928 records. Unless you have space to draw a graph almost nine thousand pixels wide then there is no point in wasting valuable rending time processing that much data. Reducing the data to one point per hour gives us a much more manageable 744 data points for a month. A full years worth of weather data consists of 105,120 records, even reducing it to one point per hour gives us 8760 points. When rendering a year&#8217;s worth of data it is clearly worth reducing the data even further, this time to one point per day.</p>
<p>How do we use CouchDB to reduce the data to one point per hour? Fortunately CouchDB&#8217;s map/reduce architecture is perfect for this type of processing. CouchDB will also cache the results of the processing automatically so it only needs to be run once rather than requiring an expensive denormalisation process each time some new data is uploaded.</p>
<p>First we need to group the five minute weather records together into groups for each hour. We could do this by taking the unix timestamp of record and rounding to the nearest hour. The problem with this approach is that the keys are included in the urls. If you can calculate unix timestamps in your head then your maths is better than mine! To make the urls more friendly we&#8217;ll use a <a href="http://www.diveintojavascript.com/projects/javascript-sprintf">Javascript implementation of sprintf</a> to build a human-friendly representation of date and time, excluding the minute component.</p>
<p><pre class="brush: jscript;">
function(doc) {
    // !code vendor/sprintf-0.6.js

    emit(sprintf(&quot;%4d-%02d-%02d %02d&quot;, doc.year, doc.month, doc.day, doc.hour), doc);
}
</pre></p>
<p>CouchDB will helpfully group documents with the same key, so all the records from the same hour will be passed to the reduce function. What you cannot guarantee though is that all the records will be passed in one go, instead you must ensure that your reduce function can operate on its own output. You can tell whether you are &#8216;rereducing&#8217; the output of the reduce function by checking the third parameter to the function.</p>
<p><pre class="brush: jscript;">
function(keys, values, rereduce) {
    var count = 0;

    var timestamp = values[0].timestamp;
    var temp_in = 0;
    var temp_out = 0;
    var abs_pressure = 0;
    var rain = 0;

    var wind_dir = [];
    for(var i=0; i&lt;8; i++) { wind_dir.push({ value: 0}); }
</pre></p>
<p>To combine the multiple records it makes sense to average most of the values. The exceptions to this are the amount of rain, which should be summed; the wind direction, which should be a count of the gusts in each direction, and the wind gust speed which should be the maximum value. Because your reduced function may be called more than once calculating the average value is not straightforward. If you simply calculate the average of the values passed in then you will be calculating the average of averages, which is not the same the average of the full original data. To work around this we calculate the average of the values and store that with the number of values. Then, when we rereduce, we multiply the average by the number of values and then average the multiplied value.</p>
<p>In the previous, simplified, code snippet we set up the variables that will hold the averages.</p>
<p><pre class="brush: jscript;">    for(var i=0; i&lt;values.length; i++) {
        var vcount;
        if(rereduce) { vcount = values[i].count } else { vcount = 1 }
</pre></p>
<p>We now loop through each of the values and work out how many weather records the value we&#8217;re processing represents. The initial pass will just represent a single record, but in the rereduce step it will be more.</p>
<p><pre class="brush: jscript;">        temp_in = temp_in + values[i].temp_in * vcount;
        temp_out = temp_out + values[i].temp_out * vcount;
        abs_pressure = abs_pressure + values[i].abs_pressure * vcount;
</pre></p>
<p>Here we build up the total values for temperature and pressure. Later we&#8217;ll divide these by the number of records to get the average. The next section adds the rain count up and selects the maximum wind gust.</p>
<p><pre class="brush: jscript;">
        rain = rain + values[i].rain;

        wind_ave = wind_ave + values[i].wind_ave * vcount;
        if(values[i].wind_gust &gt; wind_gust) { wind_gust = values[i].wind_gust; }
</pre></p>
<p>So far we&#8217;ve not really had to worry about the possibility of a rereduce, but for wind direction we need to take it into account. An individual record has a single window direction but for a hourly records we want to store the count of the number of times each direction was recorded. If we&#8217;re rereducing we need to loop through all the directions and combine them.</p>
<p><pre class="brush: jscript;">
        if(rereduce) {
            for(var j=0; j&lt;8; j++) {
                wind_dir[j][&quot;value&quot;] += values[i].wind_dir[j][&quot;value&quot;];
            }
        } else if(values[i].wind_ave &gt; 0 &amp;&amp; values[i].wind_dir &gt;= 0 &amp;&amp; values[i].wind_dir &lt; 16) {
            wind_dir[Math.floor(values[i].wind_dir/2)][&quot;value&quot;] += 1;
        }

        if(values[i].timestamp &lt; timestamp) { timestamp = values[i].timestamp; }
        count = count + vcount;
    }
</pre></p>
<p>The final stage is to build the object that we&#8217;re going to return. This stage is very straightforward, we just need to divide the numbers we calculated before by the count of the number of records. This gives us the correct average for these values.</p>
<p><pre class="brush: jscript;">    return {
            &quot;count&quot;: count,
            &quot;status&quot;: status,
            &quot;timestamp&quot;: timestamp,
            &quot;temp_in&quot;: temp_in / count,
            &quot;temp_out&quot;: temp_out / count,
            &quot;abs_pressure&quot;: abs_pressure / count,
            &quot;rain&quot;: rain,
            &quot;wind_ave&quot;: wind_ave / count,
            &quot;wind_gust&quot;: wind_gust,
            &quot;wind_dir&quot;: wind_dir,
        };
}
</pre></p>
<p>Now we have averaged the weather data into hourly chunks we can use a <tt>list</tt>, like the one described in the previous post, to display the data.</p>
<p>In the next and final post in this series I&#8217;ll discuss the <a href="http://www.welwynweather.co.uk/records">records page</a> on the weather site.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/13422316@N00/243295768/">Weather front</a> by <a href="http://www.flickr.com/photos/13422316@N00/">Paul Wordingham</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/652/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/652/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/652/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/652/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/652/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/652/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/652/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/652/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/652/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/652/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/652/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/652/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/652/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/652/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=652&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2012/01/20/back-garden-weather-in-couchdb-part-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm1.staticflickr.com/85/243295768_5f556ef303_m.jpg" medium="image">
			<media:title type="html">Weather front</media:title>
		</media:content>
	</item>
		<item>
		<title>Back Garden Weather in CouchDB (Part 3)</title>
		<link>http://andrewwilkinson.wordpress.com/2012/01/12/back-garden-weather-in-couchdb-part-3/</link>
		<comments>http://andrewwilkinson.wordpress.com/2012/01/12/back-garden-weather-in-couchdb-part-3/#comments</comments>
		<pubDate>Thu, 12 Jan 2012 13:46:17 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[couchdb]]></category>
		<category><![CDATA[couchapp]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mustache]]></category>
		<category><![CDATA[weather]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=638</guid>
		<description><![CDATA[In this series I&#8217;m describing how I used a CouchDB CouchApp to display the weather data collected by a weather station in my back garden. In the first post I described CouchApps and how to get a copy of the site. In the next post we looked at how to import the data collected by [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=638&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/dexxus/5653503758/"><img style="float:right;border:0;" src="http://farm6.staticflickr.com/5264/5653503758_077615716a_m.jpg" alt="almost may" /></a>In this series I&#8217;m describing how I used a <a href="http://www.couchdb.org">CouchDB</a> <a href="http://couchapp.org/page/index">CouchApp</a> to <a href="http://www.welwynweather.co.uk">display the weather data</a> collected by a weather station in my back garden. In the <a href="http://andrewwilkinson.wordpress.com/2011/12/02/back-garden-weather-in-couchdb-part-1/">first post</a> I described CouchApps and how to get a copy of the site. In the <a href="http://andrewwilkinson.wordpress.com/2012/01/05/back-garden-weather-in-couchdb-part-2/">next post</a> we looked at how to import the data collected by <a href="http://code.google.com/p/pywws/">PyWWS</a> and how to render a basic page in a CouchApp. In the post we&#8217;ll extend the basic page to display real weather data.</p>
<p>Each document in the database is a record of the weather data at a particular point in time. As we want to display the data over a whole day we need to use a <a href="http://wiki.apache.org/couchdb/Formatting_with_Show_and_List#Listing_Views_with_CouchDB_0.10_and_later"><tt>list</tt> function</a>. <tt>list</tt> functions work similarly to the <tt>show</tt> function we saw in the previous post. Unlike <tt>show</tt> functions <tt>list</tt> functions don&#8217;t have the document passed in, they can call a <tt>getRow</tt> function which returns the next row to process. When there are no rows left it returns <tt>null</tt>.</p>
<p><tt>show</tt> functions process an individual document and return a single object containing the processed data and any HTTP headers. Because a <tt>list</tt> function can process a potentially huge number of rows they return data in a different way. Rather than returning a single object containing the whole response <tt>list</tt> functions must return their response in chunks. First you need to call the <tt>start</tt> function, passing in any headers that you want to return. Then you call <tt>send</tt> one or more times to return parts of your response. A typical <tt>list</tt> function will look like the code below.</p>
<p><pre class="brush: jscript;">
function (head, req) {
    start({ &quot;headers&quot;: { &quot;Content-Type&quot;: &quot;text/html&quot; }});

    send(header);
    while(row = getRow()) {
        data = /* process row */;
        send(row);
    }
    send(footer);
}
</pre></p>
<p>To process the weather data we can&#8217;t follow this simple format because we need to split each document up and display the different measurements separately. Let&#8217;s look at the code for creating the day page. The complete code is a bit too long to include in a blog post so checkout the first post in this series to find out how to get a complete copy of the code.</p>
<p>To start the function we load the templates and code that we need using the CouchApp macros. Next we return the appropriate <tt>Content-Type</tt> header, and then we create the object that we&#8217;ll pass to Mustache when we&#8217;ve processed everything.</p>
<p><pre class="brush: jscript;">
function(head, req) {
    // !json templates.day
    // !json templates.head
    // !json templates.foot
    // !code vendor/couchapp/lib/mustache.js
    // !code vendor/sprintf-0.6.js
    // !code vendor/date_utils.js

    start({ &quot;headers&quot;: { &quot;Content-Type&quot;: &quot;text/html&quot; }});

    var stash = {
        head: templates.head,
        foot: templates.foot,
        date: req.query.startkey,
    };
</pre></p>
<p>Next we build a list of the documents that we&#8217;re processing so we can loop over the documents multiple times.</p>
<p><pre class="brush: jscript;">
    var rows = [];
    while (row = getRow()) {
        rows.push(row.doc);
    }
</pre></p>
<p>To calculate maximum and minimum values we need to choose the first value and then run through each piece of data and see whether it is higher or lower than the current record. As the data collector of the weather station is separate to the outside sensors occasionally they lose their connection. This means that we can just pick the value in the first document as our starting value, instead we must choose the first document where the connection with the outside sensors was made.</p>
<p><pre class="brush: jscript;">
    if(rows.length &amp;gt; 0) {
        for(var i=0; i&lt;rows.length; i++) {
            if((rows[i].status &amp;amp; 64) == 0) {
                max_temp_out = rows[i].temp_out;
                min_temp_out = rows[i].temp_out;
                max_hum_out = rows[i].hum_out;
                min_hum_out = rows[i].hum_out;

                break;
            }
        }
</pre></p>
<p>Now we come to the meat of the function. We loop through all of the documents and process them into a series of arrays, one for each graph that we&#8217;ll draw on the final page.</p>
<p><pre class="brush: jscript;">
        for(var i=0; i&lt;rows.length; i++) {
            var temp_out = null;
            var hum_out = null;
            if((rows[i].status &amp; 64) == 0) {
                temp_out = rows[i].temp_out;
                hum_out = rows[i].hum_out;

                total_rain = total_rain + rows[i].rain;
                rainfall.push({ &quot;time&quot;: time_text, &quot;rain&quot;: rows[i].rain });

                wind.push({ &quot;time&quot;: time_text, &quot;wind_ave&quot;: rows[i].wind_ave, &quot;wind_gust&quot;: rows[i].wind_gust });

            }

            pressure.push({ &quot;time&quot;: time_text, &quot;pressure&quot;: rows[i].abs_pressure });

            temps.push({ &quot;time&quot;: time_text, &quot;temp_out&quot;: temp_out, &quot;temp_in&quot;: rows[i].temp_in });

            humidity.push({ &quot;time&quot;: time_text, &quot;hum_in&quot;: rows[i].hum_in, &quot;;hum_out&quot;: hum_out });
        }
    }
</pre></p>
<p>Lastly we take the <tt>stash</tt>, which in a bit of code I&#8217;ve not included here has the data arrays added to it, and use it to render the <tt>day</tt> template.</p>
<p><pre class="brush: jscript;">
    send(Mustache.to_html(templates.day, stash));

    return &amp;quot;&amp;quot;;
}
</pre></p>
<p>Let&#8217;s look at a part of the <tt>day</tt> template. The page is a fairly standard use of the <a href="http://code.google.com/apis/chart/">Google Chart Tools</a> library. In this first snippet we render the maximum and minimum temperature values, and a blank div that we&#8217;ll fill with the chart.</p>
<p><pre class="brush: xml;">
&lt;h3&gt;Temperature&lt;/h3&gt;

&lt;p&gt;Outside: &lt;b&gt;Maximum:&lt;/b&gt; {{ max_temp_out }}&lt;sup&gt;o&lt;/sup&gt;C &lt;b&gt;Minimum:&lt;/b&gt; {{ min_temp_out }}&lt;sup&gt;o&lt;/sup&gt;C&lt;/p&gt;
&lt;p&gt;Inside: &lt;b&gt;Maximum:&lt;/b&gt; {{ max_temp_in }}&lt;sup&gt;o&lt;/sup&gt;C &lt;b&gt;Minimum:&lt;/b&gt; {{ min_temp_in }}&lt;sup&gt;o&lt;/sup&gt;C&lt;/p&gt;

&lt;div id=&quot;tempchart_div&quot;&gt;&lt;/div&gt;
</pre></p>
<p>In the following Javascript function we build a <tt>DataTable</tt> object that we pass to the library to draw a line chart. The <tt>{{#temps}}</tt> and <tt>{{/temps}}</tt> construction is the Mustache way of looping through the <tt>temps</tt> array. We use it to dynamically write out Javascript code containing the data we want to render.</p>
<p><pre class="brush: jscript;">
function drawTempChart() {
    var data = new google.visualization.DataTable();
    data.addColumn('string', 'Time');
    data.addColumn('number', 'Outside');
    data.addColumn('number', 'Inside');

    data.addRows([
    {{#temps}}
        ['{{ time }}', {{ temp_out }}, {{ temp_in }}],
    {{/temps}}
        null]);

    var chart = new google.visualization.LineChart(document.getElementById('tempchart_div'));
    chart.draw(data, {width: 950, height: 240, title: 'Temperature'});
}
google.setOnLoadCallback(drawTempChart);
</pre></p>
<p>We now have a page that displays all the collected weather data for a single day. In the next post in this series we&#8217;ll look at how to use CouchDB&#8217;s map/reduce functions to process the data so we can display it by month and by year.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/dexxus/5653503758/">almost may</a> by <a href="http://www.flickr.com/photos/dexxus/">paul bica</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/638/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/638/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/638/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/638/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/638/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/638/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/638/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/638/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/638/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/638/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/638/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/638/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/638/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/638/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=638&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2012/01/12/back-garden-weather-in-couchdb-part-3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm6.staticflickr.com/5264/5653503758_077615716a_m.jpg" medium="image">
			<media:title type="html">almost may</media:title>
		</media:content>
	</item>
		<item>
		<title>Back Garden Weather in CouchDB (Part 2)</title>
		<link>http://andrewwilkinson.wordpress.com/2012/01/05/back-garden-weather-in-couchdb-part-2/</link>
		<comments>http://andrewwilkinson.wordpress.com/2012/01/05/back-garden-weather-in-couchdb-part-2/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 13:58:04 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[couchdb]]></category>
		<category><![CDATA[couchapp]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mustache]]></category>
		<category><![CDATA[weather]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=632</guid>
		<description><![CDATA[In my last post I described the new CouchDB-based website I have built to display the weather data collected from the weather station in my back garden. In this post I&#8217;ll describe to import the data into CouchDB and the basics of rendering a page with a CouchApp. PyWWS writes out the raw data it [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=632&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/scelera/2226758824/"><img style="float:right;border:0;" src="http://farm3.staticflickr.com/2073/2226758824_a5df2b2629_m.jpg" alt="its raining..its pouring" /></a>In my <A href="http://andrewwilkinson.wordpress.com/2011/12/02/back-garden-weather-in-couchdb-part-1/">last post</a> I described the new CouchDB-based <a href="http://www.welwynweather.co.uk">website</a> I have built to display the weather data collected from the weather station in my back garden. In this post I&#8217;ll describe to import the data into CouchDB and the basics of rendering a page with a <a href="http://couchapp.org">CouchApp</a>.</p>
<p><a href="http://code.google.com/p/pywws/">PyWWS</a> writes out the raw data it collected into a series of CSV files, one per day. These are stored in two nested directory, the first being the year, the second being <tt>year-month</tt>. To collect the data I use PyWWS&#8217;s live logging mode, which consists of a process constantly running, talking to the data collector. Every five minutes it writes a new row into today&#8217;s CSV file. Another process then runs every five minutes to read the new row, and import it into the database.</p>
<p>Because CouchDB stores its data using an append only format you should aim to avoid unnecessary updates. The simplest way to write the import script would be to import each day&#8217;s data every five minutes. This would cause the database to balloon in size, so instead we query the database to find the last update time and import everything after than. Each update is stored as a separate document in the database, with the <tt>timestamp</tt> attribute containing the unix timestamp of the update. </p>
<p>The map code to get the most recent update is quite simple, we just need to emit the timestamp for each update. The reason the timestamp is emitted as the key is so we can filter the range of updates. It is also emitted as the value so we can use the timestamp in the reduce function.</p>
<p><pre class="brush: plain;">
function(doc) {
    emit(doc.timestamp, doc.timestamp);
}
</pre></p>
<p>The reduce function is a fairly simple way to calculate the maximum value of the keys. I&#8217;ve mostly included it here for completeness.</p>
<p><pre class="brush: plain;">
function(keys, values, rereduce) {
    if(values.length == 0) {
        return 0;
    }

    var m = values[0];

    for(var i=0; i&lt;values.length; i++) {
        if(values[i] &gt; m) { m = values[i]; }
    }

    return m;
}
</pre></p>
<p>You&#8217;ll find the import script that I use in the directory you cloned in the previous post, when you got a copy of the website.</p>
<p>So, we&#8217;ve got some data in our database. How do we display it on a webpage? First, let&#8217;s consider the basics of rendering a webpage.</p>
<p>CouchDB has two ways to display formatted data, <a href="http://wiki.apache.org/couchdb/Formatting_with_Show_and_List">show and list</a> functions. Show functions allow you to format a single documents, for example a blog post. List functions allow you to format a group of documents, such as a the comments on a post. Because viewing a single piece of weather data is not interesting the weather site only uses list functions. To get started let&#8217;s create a simple Show function, as these are simpler.</p>
<p>CouchApp doesn&#8217;t come with a templating library, but a common one to use is <a href="http://mustache.github.com/">Mustache</a>. The syntax is superficially like Django templates, but in reality it is far less powerful. For a simple website like this, Mustache is perfect.</p>
<p>In the <tt>show</tt> directory of your CouchApp create a new file, <tt>test.js</tt>. As with the map/reduce functions this file contains an anonymous function. In this case the function takes two parameters, the document and the request obejct, and returns an object containing the response body and any headers.</p>
<p><pre class="brush: plain;">
function (doc, req) {
    // !json templates.records
    // !json templates.head
    // !json templates.foot
    // !code vendor/couchapp/lib/mustache.js
</pre></p>
<p>The function begins with some magic comments. These are commands to CouchDB which includes the referenced code or data in the function. This allows you to keep shared data separate from the functions that uses it.</p>
<p>The first <tt><a href="http://guide.couchdb.org/draft/show.html#json">!json</a></tt> command causes the compiler to load the file <tt>templates/records.*</tt> and add it to a <tt>templates</tt> objects, under the <tt>records</tt> attribute.</p>
<p>The <tt><a href="http://guide.couchdb.org/draft/show.html#code">!code</a></tt> command works similarly, but in loads the specified file and includes the code in your function. Here we load the Mustache library, but I have also used the function to load <a href="http://www.diveintojavascript.com/projects/javascript-sprintf">a javascript implementation of <tt>sprintf</tt></a>. You might want to load some of your own common code using this method.</p>
<p><pre class="brush: plain;">
    var stash = {
        head: templates.head,
        foot: templates.foot
    };

    return { body: Mustache.to_html(templates.records, stash), headers: { &quot;Content-Type&quot;: &quot;text/html&quot; } };
}
</pre></p>
<p>Firstly we build an object containing the data we want to use in our template. As Mustache doesn&#8217;t allow you to extend templates we need to pass the header and footer HTML code in as data.</p>
<p>As mentioned the return type of a <tt>show function</tt> is a object containing the HTML and any HTTP headers. We only want to include the content type of the page, but you could return any HTTP header in a similar fashion. To generate the HTML we call the <tt>to_html</tt> function provided by Mustache, passing the template and the data object we prepared earlier.</p>
<p>Now we have data in our database and can create simple pages using a CouchApp we can move on to showing real data. In the next post I will describe the list functions use to show summarized day and month weather information.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/scelera/2226758824/">its raining..its pouring</a> by <a href="http://www.flickr.com/photos/scelera/">samantha celera</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/632/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/632/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/632/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/632/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/632/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/632/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/632/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/632/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/632/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/632/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/632/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/632/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/632/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/632/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=632&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2012/01/05/back-garden-weather-in-couchdb-part-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm3.staticflickr.com/2073/2226758824_a5df2b2629_m.jpg" medium="image">
			<media:title type="html">its raining..its pouring</media:title>
		</media:content>
	</item>
		<item>
		<title>Back Garden Weather in CouchDB (Part 1)</title>
		<link>http://andrewwilkinson.wordpress.com/2011/12/02/back-garden-weather-in-couchdb-part-1/</link>
		<comments>http://andrewwilkinson.wordpress.com/2011/12/02/back-garden-weather-in-couchdb-part-1/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 12:00:55 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[couchdb]]></category>
		<category><![CDATA[pywws]]></category>
		<category><![CDATA[weather]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=567</guid>
		<description><![CDATA[When she was younger my wife wanted to be a meteorologist. That didn&#8217;t pan out, but our recent move found us with a garden, which we&#8217;ve not had before. This gave me the opportunity to buy her a weather station. I didn&#8217;t just choose any old station though, I wanted one that did wind and [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=567&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/aigle_dore/4650548165/"><img style="float:right;border:0;" src="http://farm5.static.flickr.com/4071/4650548165_b3bb04b3ee_m.jpg" alt="Rain" /></a>When she was younger my wife wanted to be a meteorologist. That didn&#8217;t pan out, but our recent move found us with a garden, which we&#8217;ve not had before. This gave me the opportunity to buy her <a href="http://smartweather.co.uk/product.php?productid=16144&amp;cat=249&amp;page=1">a weather station</a>. I didn&#8217;t just choose any old station though, I wanted one that did wind and rain as well as the usual temperature, pressure and humidity. And, the deciding factor, a USB interface with Linux support. Fortunately the excellent <a href="http://code.google.com/p/pywws/">PyWWS</a> supports a range of weather stations, including the one I brought.</p>
<p>I&#8217;m not going to go into how I <a href="http://www.flickr.com/photos/andrew_j_w/6246463884/">mounted the system</a>, or configured PyWWS. That&#8217;s all covered in the documentation. PyWWS can produce a static website, but as someone who earns his living building websites I wanted something a bit better. <a href="http://wp.me/pkxET-6z">Continuing</a> my experiments with CouchDB I decided to build the website as a <a href="http://couchapp.org/">CouchApp</a>.</p>
<p>As well as allowing you to query your data with Javascript, CouchDB lets you display webpages directly out of your database. If you visit <a href="http://www.welwynweather.co.uk">welwynweather.co.uk</a> you&#8217;ll notice that you&#8217;re redirected to a url that contains url arguments that look a lot like those used to <a href="http://wiki.apache.org/couchdb/HTTP_view_API#Access.2BAC8-Query">query a view</a>. That&#8217;s because that&#8217;s exactly what&#8217;s going on. Things become clearer when you discover that that <a href="http://www.welwynweather.co.uk">http://www.welwynweather.co.uk</a> is an alias for <a href="http://db.welwynweather.co.uk/_design/weather/_rewrite/">http://db.welwynweather.co.uk/_design/weather/_rewrite/</a>. Now you can see a more complete CouchDB URL, albeit without the database name. <a href="http://db.welwynweather.co.uk/">db.welwynweather.co.uk</a> points to an Apache reverse proxy that routes requests through to CouchDB.</p>
<p>Over the next few posts I&#8217;ll detail how the CouchApp works, but to get started you can clone my app and poke it yourself. Once you&#8217;ve installed the <tt>couchapp</tt> command line client simply run <tt>couchapp clone http://db.welwynweather.co.uk/_design/weather</tt>. This will give you a directory, <tt>weather</tt>, that contains a number of subdirectories including <tt>templates</tt> and <tt>views</tt> which contain the complete website.</p>
<p>To deploy the site to your own server you need to create a database and then run <tt>couchapp push weather http://localhost:5984/welwynweather</tt>. Visiting <tt>http://localhost:5984/welwynweather/_design/weather/_rewrite/</tt> should show you the site. You&#8217;ll need some data though, and you can use CouchDB replication to pull my data to your server. Using Futon simply set <tt>http://db.welwynweather.co.uk/</tt> as the replication source and your database as the destination and you&#8217;ll quickly get a complete copy of the database.</p>
<p>When replicating my data you currently cannot use continuous replication. When it completes replication CouchDB calls <tt>POST /_ensure_full_commit</tt>, but obviously I&#8217;ve disabled <tt>POST</tt>, <tt>PUT</tt> and <tt>DELETE</tt> on my server. This causes replication to fail and to restart from the beginning. The data will already have been copied, but CouchDB will copy it again. If you have any ideas on how to avoid this, please answer my <a href="http://stackoverflow.com/q/8309521/2990">StackOverflow question</a>.</p>
<p>The website consists of four main pages. When you visit you are redirected to a page that shows the weather for the current day. Clicking on the date at the top of the page lets you also view the weather by month and by year. The daily weather pages show as much detail as is recorded by the station, in my case this is an update every five minutes. The monthly page is much the same except that the values are averaged across an hour. The yearly page is a bit different as it shows a single point for each day. An average temperature for each day is not that useful so we calculate the high and low for each day and display that.</p>
<p>The final page is the records page. This displays information like the highest and lowest temperature ever recorded and the heaviest rain by hour and by day. The previous three pages are all fully generated by the server. The records page is a bit different though as calculating the records in one step is a bit complicated, instead we use AJAX to load each record individually. This means we can focus on each record keeping the code simple.</p>
<p>In the next post I&#8217;ll discuss how I import data into CouchDB and the basics of rendering a page in a CouchApp.</p>
<hr />
<p>If you visit the site you may find that there is no recent weather data. This is because I run PyWWS on my <a href="http://www.mythtv.org">MythTV</a> box. Rather than running the PC all the time the weather data only updates when a programme is being recorded, or I&#8217;m watching TV.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/aigle_dore/4650548165/">Rain</a> by <a href="http://www.flickr.com/photos/aigle_dore/">Moyan Brenn</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/567/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=567&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2011/12/02/back-garden-weather-in-couchdb-part-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm5.static.flickr.com/4071/4650548165_b3bb04b3ee_m.jpg" medium="image">
			<media:title type="html">Rain</media:title>
		</media:content>
	</item>
		<item>
		<title>Programming Documentary</title>
		<link>http://andrewwilkinson.wordpress.com/2011/11/25/programming-documentary/</link>
		<comments>http://andrewwilkinson.wordpress.com/2011/11/25/programming-documentary/#comments</comments>
		<pubDate>Fri, 25 Nov 2011 12:00:18 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[bbc]]></category>
		<category><![CDATA[documentary]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[raspberryp]]></category>
		<category><![CDATA[tv]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=589</guid>
		<description><![CDATA[I&#8217;m a huge science and engineering documentary geek. I prefer watching documentaries over all other forms of television. It doesn&#8217;t really matter what the documentary is about, I&#8217;ll usually watch it. After getting ready for my wedding I had a bit of time before I had to walk down the aisle so I watched a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=589&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/chriswaits/6055083924/"><img style="float:right;border:0;" src="http://farm7.staticflickr.com/6077/6055083924_bc84c1aed0_m.jpg" alt="TV Camera man" /></a>I&#8217;m a huge science and engineering documentary geek. I prefer watching documentaries over all other forms of television. It doesn&#8217;t really matter what the documentary is about, I&#8217;ll usually watch it. After getting ready for my wedding I had a bit of time before I had to walk down the aisle so I watched a documentary about pilots learning to land <A href="http://en.wikipedia.org/wiki/Marine_One">Marine One</a> at the White House. There probably aren&#8217;t many people who would choose to spend that time that way.</p>
<p>Science documentaries have experienced a renaissance over the last few years, particularly on the BBC. The long running <a href="http://www.bbc.co.uk/programmes/b006mgxf">Horizon</a> series has been joined by a raft of other mini-series presented by Brian Cox, Alice Roberts, Marcus Du Sutoy, Jim Al-Kalili and Michael Mosely. These cover a large part of the sciences, including Chemistry, Biology and Physics. Physics in particular is regularly on our screens. Whether it&#8217;s talking about quantum mechanics or astronomy or something else it seems that Physics has never been more popular.</p>
<p>As someone who writes computer programmes for a living this makes me worry that your average man on the street may end up with a better understanding of quantum mechanics than they do of the computer on their desk, or in their pocket.</p>
<p>It wasn&#8217;t always like this. Back in 1981 the BBC ran the <a href="http://www.mcmordie.co.uk/acornhistory/bbchist.shtml">BBC Computer Literacy project</a>, which attempted to teach the public to program using the <a href="http://en.wikipedia.org/wiki/BBC_Micro">BBC Micro</a> through a <a href="http://www.computinghistory.org.uk/det/7182/BBC-Computer-Literacy-Project/">ten part television series</a>.</p>
<p>Clearly if a project like this was to be attempted today there would be no need for the BBC to partner with hardware manufactures. People have access to many different programmable devices, they just don&#8217;t know how to program them.</p>
<p>Recent programs that have focused on computers were Rory Cellan Jones&#8217; <a href="http://www.bbc.co.uk/podcasts/series/shsn">Secret History of Social Networking</a> and <a href="http://www.bbc.co.uk/programmes/b00n4j0r">Virtual Revolution</a> by Aleks Krotoski. Neither of these were technical documentaries, instead they focused on business, cultural and sociological impacts of computers and the internet.</p>
<p>It&#8217;s not that more technical aspects of computer don&#8217;t appear as part of other documentaries, recently Marcus Du Sautoy <a href="https://twitter.com/#!/MarcusduSautoy/status/138678273323438080">announced</a> that he is filming a episode of Horizon on Artificial Intelligence. It won&#8217;t air until next spring, so it&#8217;s hard to comment, but I suspect it will focus on the outcome of the software rather than the process of how computers can be made to appear intelligent.</p>
<p>Jim Al-Kalili&#8217;s recent series on the history of electricity, <a href="http://www.bbc.co.uk/programmes/p00kjq6h">Shock and Awe</a>, ends with a section on the development of the transistor. During it, and over a picture of the LHC, he says something rather interesting.</p>
<blockquote><p>
Our computer&#8217;s have become so powerful that they are helping us to understand the universe in all its complexity.
</p></blockquote>
<p><a href="http://www.flickr.com/photos/11304375@N07/2046228644/"><img style="float:left;border:0;" src="http://farm3.staticflickr.com/2326/2046228644_05507000b3_m.jpg" alt="The Large Hadron Collider/ATLAS at CERN" /></a>If you don&#8217;t understand computers it&#8217;s impossible to understand how almost all modern science is done. Researches in all disiplinces need to be proficent at programming in order to anaylse their own data. Business is run on software, often which is customised to the individual requirements of the company. It boggles my mind that people can be so reliant on computers yet have so little idea of how they work.</p>
<p>So, what would my ideal programming documentary cover? The most obvious thing is the internet. A history of computer networking could begin at the development of the first computer networks, describe how TCP/IP divides data into packets and routes it between computers. It could move on to HTTP and HTML both of which are fundamentally simple yet apply to our everyday lives. To bring things up to date it could focus on  Google and Facebook and show people the inside of a data centre. I suspect that most people have no idea where their Google search results are coming from.</p>
<p>I doubt that there is much demand for the updated series as long as the 10 part original, but the soon to be released <a href="http://www.raspberrypi.org/">Raspberry Pi</a> machine would be an ideal way to recreate the tinkering appeal of the original BBC Micro. There&#8217;s something magical about seeing a program you&#8217;ve written appearing on the TV in your living room, rather than on the screen of your main PC. An alternative would be to provide an interpreter as part of a website so you can just type in a URL and start programming.</p>
<p><a href="http://www.flickr.com/photos/psd/6130124670/"><img style="float:right;border:0;" src="http://farm7.staticflickr.com/6202/6130124670_5057d0d3b6_m.jpg" alt="Raspberry PI" /></a>A documentary focussing on programming would have a difficulty that the original series never had &#8211; the fact that computing power is common place means that people are used to software created by large teams with dedicated designers. An individual with no experience can&#8217;t hope to come to close to something like that. Fortunately computers are so much more powerful today that much of the complexity that you needed to cope with can be abstracted away. Libraries like <a href="http://vpython.org/">VPython</a> make it very simple to produce complicated and impressive 3D graphics.</p>
<p>I&#8217;m certainly not the only person who wants to help teach the masses to program, but realistically you need an organisation like the BBC to do something that might actually make a difference. Do I think that you create a compelling and informative documentary that might inspire people to program, and give them a very basic understand of how to do it. Definitely.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/chriswaits/6055083924/">TV Camera man</a> by <a href="http://www.flickr.com/photos/chriswaits/">Chris Waits</a>.<br />
Photo of <a href="http://www.flickr.com/photos/11304375@N07/2046228644/">The Large Hadron Collider/ATLAS at CERN</a> by <a href="http://www.flickr.com/photos/11304375@N07/">Image Editor</a>.<br />
Photo of <a href="http://www.flickr.com/photos/psd/6130124670/">Raspberry PI</a> by <a href="http://www.flickr.com/photos/psd/">Paul Downey</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/589/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/589/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/589/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/589/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/589/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/589/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/589/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/589/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/589/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/589/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/589/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/589/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/589/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/589/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=589&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2011/11/25/programming-documentary/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm7.staticflickr.com/6077/6055083924_bc84c1aed0_m.jpg" medium="image">
			<media:title type="html">TV Camera man</media:title>
		</media:content>

		<media:content url="http://farm3.staticflickr.com/2326/2046228644_05507000b3_m.jpg" medium="image">
			<media:title type="html">The Large Hadron Collider/ATLAS at CERN</media:title>
		</media:content>

		<media:content url="http://farm7.staticflickr.com/6202/6130124670_5057d0d3b6_m.jpg" medium="image">
			<media:title type="html">Raspberry PI</media:title>
		</media:content>
	</item>
		<item>
		<title>Sonos Review</title>
		<link>http://andrewwilkinson.wordpress.com/2011/11/18/sonos-review/</link>
		<comments>http://andrewwilkinson.wordpress.com/2011/11/18/sonos-review/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 14:08:36 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[review]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[sonos]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=600</guid>
		<description><![CDATA[Recently I purchased a basic Sonos system, and after just a couple of weeks I&#8217;m already in love with it and have more music playing in my house than ever before. For those of you who haven&#8217;t come across Sonos before, Sonos produce a multi-room wireless music system. The system consists of a number of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=600&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/rwetzlmayr/5173125040/in/pool-1323024@N21/"><img style="float:right;border:0;" src="http://farm5.static.flickr.com/4133/5173125040_406a25966a_m.jpg" alt="Sonos S5" /></a>Recently I purchased a basic <a href="http://www.sonos.com/">Sonos system</a>, and after just a couple of weeks I&#8217;m already in love with it and have more music playing in my house than ever before.</p>
<p>For those of you who haven&#8217;t come across Sonos before, Sonos produce a multi-room wireless music system. The system consists of a number of devices that connect to each other using a proprietary mesh network. You can buy Sonos devices that contain built in speakers, or ones that connect to your own as well as a device to link your iPhone and to join your existing network to the Sonos wireless network.</p>
<p>I purchased a <a href="http://www.amazon.co.uk/gp/product/B005CI5H3U/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=indiegicouk-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=B005CI5H3U">Sonos Play:3</a>, a <a href="http://www.amazon.co.uk/gp/product/B0047ZFXTM/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=indiegicouk-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=B0047ZFXTM">Wireless Dock</a> and <a href="http://www.amazon.co.uk/gp/product/B000YGIJ62/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=indiegicouk-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=B000YGIJ62">ZoneBridge</a> (all three links contain an affiliate id) so that&#8217;s what I&#8217;m reviewing here.</p>
<p>The Sonos Play:3 is as fairly small, unassuming, single speaker block. It contains three individual speakers while it&#8217;s larger brother, the <a href="http://www.amazon.co.uk/gp/product/B002RL9KZG/ref=as_li_ss_tl?ie=UTF8&amp;tag=indiegicouk-21&amp;linkCode=as2&amp;camp=1634&amp;creative=19450&amp;creativeASIN=B002RL9KZG">Play:5</a> (affiliate link) contains five. The back has a power socket and a network port. The top has a mute button, as well as a volumn up and down rocker. The other devices are similarly spartan, yet stylish, in their design with minimal on device buttons.</p>
<p>First you need to plug the bridge into your network using the supplied ethernet cable. Then, after installing the PC software, or their iPhone app, you can create a Sonos network. Just follow the on screen prompts and press the &#8216;join&#8217; button on the device. For each of your other Sonos devices plug them in, select &#8220;Add new device&#8221; in the software on on the app, press the &#8216;Join&#8217; button (or Mute + Volumn Up on the Play:3) and the new device will be found and added the network.</p>
<p>The setup is supposed to be quick and straightforward, and for the first two devices it was. When I tried to add my Play:3 to the network it would repeatedly not be found. The white light on the top of the device stopped flashing, indicating that it had connected but the PC software did not find it. It&#8217;s not clear what happened, but I may have plugged it in before the previous device had finished configuring. Doing a <a href="http://sonos.custhelp.com/cgi-bin/sonos.cfg/php/enduser/std_adp.php?p_faqid=250&amp;p_created=1109033213&amp;p_sid=VIbVUpJk&amp;p_accessibility=0&amp;p_redirect=&amp;p_lva=&amp;p_sp=cF9zcmNoPTEmcF9zb3J0X2J5PSZwX2dyaWRzb3J0PSZwX3Jvd19jbnQ9OCw4JnBfcHJvZHM9JnBfY2F0cz0mcF9wdj0mcF9jdj0mcF9zZWFyY2hfdHlwZT1hbnN3ZXJzLnNlYXJjaF9mbmwmcF9wYWdlPTEmcF9zZWFyY2hfdGV4dD1yZXNldA**&amp;p_li=&amp;p_topview=1">factory reset</a> solved the issue.</p>
<p>The simplest thing to play on the Sonos system is internet radio. The controller comes preloaded with a huge range of radio stations. Just select the one you want and after a short pause it&#8217;ll come out of your speaker, on the other side of the room. Not only is process of listening to the radio incredibly simple, but the sound from such a small box is amazing. I&#8217;m not an audiophile, but it was loud, clear and had plenty of bass.</p>
<p><a href="http://www.sonos.com/shop/products/play3"><img src="http://andrewwilkinson.files.wordpress.com/2011/11/play3blkiphone.jpg?w=300&#038;h=225" alt="" title="Sonos Play:3 and iPhone" width="300" height="225" style="border:0;" class="alignleft size-medium wp-image-612" /></a>To play your own music collection you need to have it available on a Windows share. I already had this set up so I just had to tell Sonos where to find it. After short while it had crawled my complete collection and I could select by artist, album, track or genre right from my iPhone. As with the radio it&#8217;s quick to start playing and the sound quality is excellent.</p>
<p>It was at this point that I came across the first of the few bugs I&#8217;ve found with the Sonos system. Originally I had ripped my music into Ogg Vorbis format. Then, when I got my iPhone I had to rerip it as MP3. Some of my albums have both Ogg and MP3 files of the same music, in the same directory. The Sonos player does not appear to like this, and although it can play both formats neither would appear in the controller. Where only one copy exists the files were found with no problems.</p>
<p>I also had some difficulties when my network was heavily loaded. While upgrading one of my pcs to the latest Ubuntu and listening to some music it skipped heavily and eventually the Play:3 crashed. Another issue is that my music is stored on my MythTV box which turns itself on and off to record tv. I forgot to lock the box so it switched itself off mid-track. Somewhat annoyingly the Play:3 stopped playing mid-track as well. I would have thought that the Sonos would have enough memory to have cached at least the whole track, if not the whole playlist.</p>
<p>The iPhone dock is a very useful addition to my house, if only because I just have to slip my phone in and it starts charging. It is certainly much easier to connect than a cable, and much tidier too. Unfortunately you cannot stream music from your iPhone/iPod Touch unless it is placed in the dock. This is a limitation imposed by Apple rather than Sonos, so I have to forgive them. When it&#8217;s placed in the dock any sound your device makes will be played through your speaker. This works great when you&#8217;re playing some music or a podcast through your phone, but I had a timer set on my phone which was charging while I listened some internet radio. While surprising this is just it working as expected, and you can turn off the autoplay feature.</p>
<p>I have my old iPhone 3G as well as much newer iPhone 4S, and if I want to keep my MythTV box off I can dock the old phone and browse its music selection and select what to listen to from the 4S. This is the real power of the Sonos concept &#8211; all your music, everywhere in your house.</p>
<p>The criticisms I&#8217;ve made are small points, and despite only having my system for just two weeks I already can&#8217;t imagine life without it. I&#8217;m willing to forgive the somewhat high price and am saving my pennies to buy another couple of either Play:5 or Play:3s to spread around the house.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/rwetzlmayr/5173125040/in/pool-1323024@N21/">Sonos S5</a> by <a href="http://www.flickr.com/photos/rwetzlmayr/">Robert Wetzlmayr</a>.<br />
Photo of Play:3 and iPhone courtesy of <a href="http://www.sonos.com">Sonos</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/600/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/600/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/600/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/600/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/600/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/600/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/600/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/600/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/600/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/600/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/600/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/600/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/600/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/600/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=600&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2011/11/18/sonos-review/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm5.static.flickr.com/4133/5173125040_406a25966a_m.jpg" medium="image">
			<media:title type="html">Sonos S5</media:title>
		</media:content>

		<media:content url="http://andrewwilkinson.files.wordpress.com/2011/11/play3blkiphone.jpg?w=300" medium="image">
			<media:title type="html">Sonos Play:3 and iPhone</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone on Holiday</title>
		<link>http://andrewwilkinson.wordpress.com/2011/11/11/iphone-on-holiday/</link>
		<comments>http://andrewwilkinson.wordpress.com/2011/11/11/iphone-on-holiday/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 12:00:51 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[iphone]]></category>
		<category><![CDATA[autostitch]]></category>
		<category><![CDATA[camera]]></category>
		<category><![CDATA[dermandar]]></category>
		<category><![CDATA[imovie]]></category>
		<category><![CDATA[photography]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=587</guid>
		<description><![CDATA[Recently I posted about upgrading my old iPhone 3G to a 64GB 4S. One of the things I was mostly looking forward to with the upgrade was the much improved camera and the ability to take video. Last week I spent some time at the Giant&#8217;s Causeway in Northern Ireland and I had plenty of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=587&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/johnlembo/2402051626/"><img style="float:right;border:0;" src="http://farm4.static.flickr.com/3057/2402051626_0fbb1ab392_m.jpg" alt="iPhone at the beach" /></a>Recently I <a href="http://andrewwilkinson.wordpress.com/2011/10/17/iphone-4s/">posted</a> about upgrading my old iPhone 3G to a 64GB 4S. One of the things I was mostly looking forward to with the upgrade was the much improved camera and the ability to take video. Last week I spent some time at the <a href="http://www.giantscausewayireland.com/">Giant&#8217;s Causeway</a> in Northern Ireland and I had plenty of opportunity to experiment with both the still and video camera.</p>
<p>Although it&#8217;ll never replace my DSLR the stills camera managed to take some really respectable shots. By far the biggest issue is the lack of a zoom. The colours are great, the focus is sharp but you can&#8217;t use the zoom to frame a shot. You need to move if you want to change what&#8217;s in your shot.</p>
<p>The video camera is also excellent. The pictures are bright, crisp and clear and it&#8217;s very easy to start recording. The small size of the iPhone makes it very easy to move the camera around. Movement is not something I&#8217;d had to think about before have previously only used a stills camera, but a static video shot gets boring very quickly.</p>
<p>The audio quality is quite poor, at least when you are in a windy location, and as I was on the coast it was nearly always windy. The white noise of the wind masked much of the voice that I was trying to record. Unfortunately I can&#8217;t afford a <a href="http://en.wikipedia.org/wiki/Foley_(filmmaking)">Foley</a> artist so the wind noise remains on the final version.</p>
<p>To edit my travelogue there was really only one option, <a href="http://itunes.apple.com/gb/app/imovie/id377298193?mt=8">iMovie</a>. As iMovie runs on the iPhone you don&#8217;t need to move your video files and get start editing straightaway. Each evening in our hotel room I could review the footage and start the editing process.</p>
<p>A touch interface is a natural fit for video editing work, but almost as soon as you start using iMovie you begin to realise the limitations of it. Both rearranging and deleting clips should be possible by drapping them. Instead I found it very hard to make iMovie recognise my dragging, it repeatedly selected the clip instead. Also trimming clips is difficult to do accurately because you cannot drag to frame level accuracy. While dragging the timeline around it also had the annoying habit of scrolling back to the start rather than the small adjustment I was trying to make.</p>
<p>The themes included with iMovie are quite nice, but as is the case with the whole app very soon after you start using them you really how limited they are. The two main problem is that when joining clips together you are limited to either a simple jump cut, cross fade or a single theme specific transition. It&#8217;s certainly important not to over use transitions, but having a few more options would be nice. You&#8217;re also extremely limited when adding text to the video, which is a key part of making a travelogue video.</p>
<p>I took some panorama photos using my iPhone as they&#8217;re a great way to show a scene that you just can&#8217;t capture with an ordinary camera. The first app I tried was <a href="http://itunes.apple.com/gb/app/dermandar-panorama/id441183050?mt=8">Dermandar</a>. This app is incredibly easy to use. You hold the camera vertically and then rotate it and the app captures pictures automatically and then stitches them together. The resulting panorama&#8217;s look great, until you try and take them off your phone. Part of the ease of use comes from the fact that it uses the video camera rather than stills camera so it&#8217;s much quicker to take the pictures. This is much lower resolution though so the resulting images are disappointing small.</p>
<p>The next app I tried was <a href="http://www.cloudburstresearch.com/autostitch/autostitch.html">Autostitch panorama</a>. Rather than the pictures being taken automatically you need to line up your photos and press a button to take a picture. When you&#8217;ve captured enough click &#8220;finish&#8221; and the app will stitch them together very quickly, producing great looking full panoramas. It&#8217;s not quite as simple to use as Dermandar, but it&#8217;s far from difficult and the results are excellent.</p>
<p>I&#8217;m not quite ready to leave my DSLR permanently at home, but there are certainly occasions when I will think twice about lugging it around with me.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/johnlembo/2402051626/">iPhone at the beach</a> by <a href="http://www.flickr.com/photos/johnlembo/">John_DL</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/587/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=587&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2011/11/11/iphone-on-holiday/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm4.static.flickr.com/3057/2402051626_0fbb1ab392_m.jpg" medium="image">
			<media:title type="html">iPhone at the beach</media:title>
		</media:content>
	</item>
		<item>
		<title>Exceptional Catches</title>
		<link>http://andrewwilkinson.wordpress.com/2011/11/02/exceptional-catches/</link>
		<comments>http://andrewwilkinson.wordpress.com/2011/11/02/exceptional-catches/#comments</comments>
		<pubDate>Wed, 02 Nov 2011 12:00:18 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[exceptions]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=396</guid>
		<description><![CDATA[Recently I was taking part in a review of some Python code. One aspect of the code really stuck out to me. It&#8217;s not a structural issue, but a minor change in programming style that can greatly improve the maintainability of the code. The code in general was quite good, but a code snippet similar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=396&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/biggleswadeblue/3206950603/"><img style="float:right;border:0;" src="http://farm4.static.flickr.com/3382/3206950603_b6449c2067_m.jpg" alt="Throw In" /></a>Recently I was taking part in a review of some Python code. One aspect of the code really stuck out to me. It&#8217;s not a structural issue, but a minor change in programming style that can greatly improve the maintainability of the code.</p>
<p>The code in general was quite good, but a code snippet similar to that given below jumped right to the top of my list of things to be fixed. Why is this so bad? Let us first consider what exceptions are and why you might use them in Python.</p>
<p><pre class="brush: python;">
try:
    // code
except Exception, e:
    // error handling code
</pre></p>
<p>Exceptions are a way of breaking out the normal program flow when an &#8216;exceptional&#8217; condition arises. Typically this is used when errors occur, but exceptions can also be used as an easy way to break out of normal flow during normal but unusual conditions. In a limited set of situations it can make program flow clearer.</p>
<p>What does this code do though? It catches all exceptions, runs the error handling code and continues like nothing has happened. In all probability it&#8217;s only one or two errors that are expected and should be handled. Any other errors should be passed on a cause the program to actually crash so it can be debugged properly.</p>
<p>Let&#8217;s consider the following code:</p>
<p><pre class="brush: python;">
analysis_type = 1
try:
    do_analysis(analysis_typ)
except Exception, e:
    cleanup()
</pre></p>
<p>This code has a bug, the missing <tt>e</tt> in the <tt>do_analysis</tt> call. This will raise a <tt>NameError</tt> that will be immediately captured and hidden. Other, more complicated errors could also occur and be hidden in the same way. This sort of masking will make tracking down problems like this very difficult.</p>
<p>To improve this code we need to consider what errors we expect the <tt>do_analysis</tt> function to raise and what we want to handle. In the ideal case it would raise an <tt>AnalysisError</tt> and then we would catch that.</p>
<p><pre class="brush: python;">
analysis_type = 1
try:
    do_analysis(analysis_typ)
except AnalysisError, e:
    cleanup()
</pre></p>
<p>In the improved code the <tt>NameError</tt> will pass through and be picked up immediately. It is likely that the <tt>cleanup</tt> function needs to be run whether or not an error has occurred. To do that we can move the call into a <tt>finally</tt> block.</p>
<p><pre class="brush: python;">
analysis_type = 1
try:
    do_analysis(analysis_typ)
except AnalysisError, e:
    // display error message
finally:
    cleanup()
</pre></p>
<p>This allows us to handle a very specific error and ensure that we clean up whatever error happens. Sometimes cleaning up whatever the exception (or in the event of no exception) is required, and in this case the finally block, which is always run, is the right place for this code.</p>
<p>Let&#8217;s now consider a different piece of code.</p>
<p><pre class="brush: python;">
try:
    do_analysis(analysis_types[index])
except KeyError:
    // display error message
</pre></p>
<p>We&#8217;re looking up the parameter to <tt>do_analysis</tt> in a dictionary and catching the case where <tt>index</tt> doesn&#8217;t exist. This code is also capturing too much. Not because the exception is too general, but because there is too much code in the <tt>try</tt> block.</p>
<p>The issue with this code is what happens if <tt>do_analysis</tt> raises a <tt>KeyError</tt>? To capture the exceptions that we&#8217;re expecting we need to only wrap the dictionary lookup in and not catch anything from the analysis call.</p>
<p><pre class="brush: python;">
try:
    analysis_type = analysis_types[index]
except KeyError:
    // display error message
finally:
    do_analysis(analysis_type)
</pre></p>
<p>So, if I&#8217;m reviewing your code don&#8217;t be afraid to write a few extra lines in order to catch the smallest, but correct, set of exceptions.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/biggleswadeblue/3206950603/">Throw In</a> by <a href="http://www.flickr.com/photos/biggleswadeblue/">Nick Treby</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/396/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=396&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2011/11/02/exceptional-catches/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm4.static.flickr.com/3382/3206950603_b6449c2067_m.jpg" medium="image">
			<media:title type="html">Throw In</media:title>
		</media:content>
	</item>
		<item>
		<title>New Delicious</title>
		<link>http://andrewwilkinson.wordpress.com/2011/10/26/new-delicious/</link>
		<comments>http://andrewwilkinson.wordpress.com/2011/10/26/new-delicious/#comments</comments>
		<pubDate>Wed, 26 Oct 2011 11:00:59 +0000</pubDate>
		<dc:creator>Andrew Wilkinson</dc:creator>
				<category><![CDATA[other websites]]></category>
		<category><![CDATA[bookmarks]]></category>
		<category><![CDATA[delicious]]></category>

		<guid isPermaLink="false">http://andrewwilkinson.wordpress.com/?p=508</guid>
		<description><![CDATA[I&#8217;ve been a long time user of delicious.com, back from when it was had the hard-to-remember address of del.icio.us. Even though bookmark syncing is built into both Firefox and Chrome having your bookmarks available on a website that you can access from anywhere, and integrated into your browser using an extension is a big advantage [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=508&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/adulau/5610614157/"><img style="float:right;border:0;" src="http://farm6.static.flickr.com/5301/5610614157_e69f61f829_m.jpg" alt="delicious or del.icio.us?" /></a>I&#8217;ve been a long time user of <a href="http://www.delicious.com">delicious.com</a>, back from when it was had the hard-to-remember address of <a href="http://del.icio.us/">del.icio.us</a>. Even though bookmark syncing is built into both <A href="https://services.mozilla.com/">Firefox</a> and <a href="http://www.google.co.uk/support/chrome/bin/answer.py?answer=185277">Chrome</a> having your bookmarks available on a website that you can access from anywhere, and integrated into your browser using an extension is a big advantage for me.</p>
<p>Recently the was some cause for concern as Yahoo decided they wanted to offload the site. As it had been a Yahoo property for a long time anyone taking it on would have a big job just to extricate it from Yahoo&#8217;s infrastructure. <a href="http://avos.com/">AVOS</a>, a new venture from the founders of YouTube took the plunge.</p>
<p>Several months on and the site suddenly relaunched. Superficially it looks very similar, but with a slight Web 2.0 sheen to it. The transition seems to have been handled very well given the scale of the rewrite that was required. Aside from a smattering of bugs which have been quickly squashed the biggest issue seems to have been with the people who ignored the warnings and didn&#8217;t agree to allow Yahoo to send AVOS their details.</p>
<p>The biggest change is the addition of <a href="http://delicious.com/help#stack">stacks</a>. These are curated sets of links on a single topic. While the old Delicious showed popular links on the frontpage the new site shows featured stacks. As you can associate an image with a stack this gives the frontpage a much more visual look. The old website was undeniably plain and the images really brighten it up.</p>
<p>Like many people when the Delicious troubles surfaced I immediately looked for an alternative. The most obvious choice is <a>Google Bookmarks</a>. Very quickly they produced a <a href="https://www.google.com/bookmarks/deliciousimport">tool</a> that imported your bookmark from Delicious making any potential switch very easy.</p>
<p>Should you make the switch though?</p>
<p>I&#8217;m glad I held off as the only advantage Google has is the closer integration with Chrome. The site is just a big list of sites with none of the social features present in Delicious. While Bookmarks might be suitable for just keeping a small list of links, Delicious&#8217; better organization tools and style really help to manage a big list.</p>
<p>My biggest concern with the new site is the same as my concern with the old one. The business model, or rather, lack of. Delicious has never displayed adverts, never had any premium features and in fact has never had a way to make money (that I know of at least). Do the new owners have plan to make it profitable? I hope so, but it&#8217;s hard to imagine what feature you could add that would make people pay and taking features away is likely to create a huge backlash.</p>
<p>In short I&#8217;m delighted to see Delicious rise from the troubles that it faced looking stronger and better than ever.</p>
<hr />
<p>Photo of <a href="http://www.flickr.com/photos/adulau/5610614157/">delicious or del.icio.us?</a> by <a href="http://www.flickr.com/photos/adulau/">Alexandre Dulaunoy</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andrewwilkinson.wordpress.com/508/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andrewwilkinson.wordpress.com/508/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andrewwilkinson.wordpress.com/508/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andrewwilkinson.wordpress.com/508/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andrewwilkinson.wordpress.com/508/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andrewwilkinson.wordpress.com/508/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andrewwilkinson.wordpress.com/508/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andrewwilkinson.wordpress.com/508/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andrewwilkinson.wordpress.com/508/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andrewwilkinson.wordpress.com/508/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andrewwilkinson.wordpress.com/508/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andrewwilkinson.wordpress.com/508/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andrewwilkinson.wordpress.com/508/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andrewwilkinson.wordpress.com/508/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andrewwilkinson.wordpress.com&amp;blog=4895947&amp;post=508&amp;subd=andrewwilkinson&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andrewwilkinson.wordpress.com/2011/10/26/new-delicious/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0d5abb071bb1ab8518c3e9b0f4e718eb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Andrew</media:title>
		</media:content>

		<media:content url="http://farm6.static.flickr.com/5301/5610614157_e69f61f829_m.jpg" medium="image">
			<media:title type="html">delicious or del.icio.us?</media:title>
		</media:content>
	</item>
	</channel>
</rss>
