<?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"
	>

<channel>
	<title>LShift Ltd.</title>
	<atom:link href="http://www.lshift.net/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.lshift.net/blog</link>
	<description>What happens at LShift</description>
	<pubDate>Sat, 21 Aug 2010 20:07:46 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Some relational algebra with datatypes in Clojure 1.2</title>
		<link>http://www.lshift.net/blog/2010/08/21/some-relational-algebra-with-datatypes-in-clojure-12</link>
		<comments>http://www.lshift.net/blog/2010/08/21/some-relational-algebra-with-datatypes-in-clojure-12#comments</comments>
		<pubDate>Sat, 21 Aug 2010 20:07:46 +0000</pubDate>
		<dc:creator>tim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=549</guid>
		<description><![CDATA[Clojure 1.2 has been released and Leiningen has moved up to 1.3.0 (or was it briefly 1.2.0) which supports the latest version - so I decided to spend a spare afternoon playing with one of the new features of Clojure.

One of the interesting new features is datatypes which are a replacement for the structmap feature [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://clojure.blogspot.com/2010/08/clojure-12-release.html">Clojure 1.2 has been released</a> and <a href="http://github.com/technomancy/leiningen">Leiningen has moved up to 1.3.0 (or was it briefly 1.2.0)</a> which supports the latest version - so I decided to spend a spare afternoon playing with one of the new features of Clojure.</p>

<p>One of the interesting new features is datatypes which are a replacement for the structmap feature from earlier versions of Clojure. Datatypes and structmaps are directly equivalent to maps. Clojure provides an implementation of relational algebra that works on its maps in the clojure.set namespace, I expected that these functions should work with datatypes but I decided to check for myself.</p>

<p><span id="more-549"></span></p>

<p>I specifically wanted to check how close you an approach to an ideal relational system as defined by C. J Date in his books - Database in Depth and Databases, Types, and the Relational Model: The Third Manifesto. Date strongly believes that databases should be built on relational algebra and that none of the current relational databases achieve that goal. Database in Depth is a very readable and concise introduction to relational algebra and is well worth reading.</p>

<p>clojure.set contains six functions that correspond to the six fundamental operations in relational algebra - union, difference, rename, selection, projection and join. The first two, union and difference, are simple set operations that will definitely work on sets of datatypes. Let us try the other four operators on some datatypes, I&#8217;ll base my examples on a cut-down set of relations used by Date describing suppliers, parts and shipments.</p>

<p>A clojure datatype is created using the defrecord function. We will a datatype for a supplier, a part and a shipment:</p>

<pre><code>
(defrecord Supplier [number name status city])
(defrecord Part [number name colour weight city])
(defrecord Shipment [supplier part quantity])
</code></pre>

<p>We can create a supplier like this:</p>

<pre><code>
(Supplier. "S1" "Supplier 1" 100 "London")
</code></pre>

<p>We can then define our three relations like this:</p>

<pre><code>
(def suppliers
  #{(Supplier. "S1" "Smith" 20 "London")
    (Supplier. "S2" "Jones" 10 "Paris")
    (Supplier. "S3" "Blake" 30 "Paris")})
(def parts
  #{(Part. "P1" "Nut" "Red" 12.0 "London")
    (Part. "P2" "Bolt" "Green" 17.0 "Paris")
    (Part. "P3" "Screw" "Blue" 17.0 "Oslo")})
(def shipments
  #{(Shipment. "S1" "P1" 300)
    (Shipment. "S2" "P2" 200)
    (Shipment. "S3" "P3" 400)})
</code></pre>

<p>Now let us try the first relational operation rename:</p>

<pre><code>
clojure.core=&gt; (use 'clojure.set)
nil
clojure.core=&gt; (rename parts {:number :id :city :location})
 #{{:location "London", :name "Nut", :colour "Red", :weight 12.0, :id "P1"}
 {:location "Paris", :name "Bolt", :colour "Green", :weight 17.0, :id "P2"}
 {:location "Oslo", :name "Screw", :colour "Blue", :weight 17.0, :id "P3"}}
</code></pre>

<p>So this results in a new map based on the parts relation with the number and city fields renamed to id and location respectively.</p>

<p>Now let us try a select operation:</p>

<pre><code>
clojure.core=&gt; (select #(= (:name %) "Smith") suppliers)
#{#:Supplier{:number "S1", :name "Smith", :status 20, :city "London"}}
</code></pre>

<p>Note in this case the set that has been returned contains the datatype defined earlier not a simple map.</p>

<p>Now let us try the project operation:</p>

<pre><code>
clojure.core=&gt; (project suppliers [:city])
#{{:city &#8220;London&#8221;} {:city &#8220;Paris&#8221;}}
</code></pre>

<p>Finally let us join the parts and shipments relations:</p>

<pre><code>
clojure.core=&gt; (join parts shipments {:number :part})
#{#:Part{:number "P1", :name "Nut", :colour "Red", :weight 12.0, :city "London", :quantity 300, :part "P1", :supplier "S1"}}
</code></pre>

<p>Note that the results here is a set of the datatype Part with the additional joined fields held as additional fields on Part.</p>

<p>So this seems to work perfectly, it is also transitive, for example:</p>

<pre><code>
(project 
    (join 
      (select #(= (:city %) "Paris") 
      suppliers) shipments {:number :supplier}) 
    [:name])
</code></pre>

<p>This will produce the name of the suppliers that have shipped parts and are located in Paris.</p>

<p>So all is good with relational algebra with datatypes in Clojure! Not quite, C J Date is a bit more picky than that, he really doesn&#8217;t like null values, his ideal system has no place for null values. Clojure has a null value, nil, and any value can be nil. So I can create a record in which all values are nil, for example:</p>

<pre><code>
clojure.core=> (Supplier. nil nil nil nil) 
#:Supplier{:number nil, :name nil, :status nil, :city nil}
</code></pre>

<p>Oh no - there are unknown values! We could create a factory function that ensured that you can&#8217;t pass in any nils but you can still do this:</p>

<pre><code>
clojure.core=> (assoc (Supplier. 1 "A" 20 "London") :number nil)
#:Supplier{:number nil, :name "A", :status 20, :city "London"}
clojure.core=> 
</code></pre>

<p>So nil can still worm its way in to the datatype and we&#8217;ve introduced unknown values into our relational algebra which we probably don&#8217;t want to do. So more work is needed to satisfy C J Date. However, the core operations from clojure.set have done remarkably well and it could easily sit in the core of a relational system with some wrapping to keep the evil nil at bay.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/08/21/some-relational-algebra-with-datatypes-in-clojure-12/feed</wfw:commentRss>
		</item>
		<item>
		<title>&#8220;Nearby art&#8221;: using the V&#038;A API and geolocation</title>
		<link>http://www.lshift.net/blog/2010/07/16/nearby-art-using-the-va-api-and-geolocation</link>
		<comments>http://www.lshift.net/blog/2010/07/16/nearby-art-using-the-va-api-and-geolocation#comments</comments>
		<pubDate>Fri, 16 Jul 2010 15:34:46 +0000</pubDate>
		<dc:creator>Tom Parker</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Rant]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=548</guid>
		<description><![CDATA[A little while back, I was informed that the V&#38;A had an API. To be honest, my first response to this was &#8220;why on earth?&#8221;. There&#8217;s been a few similar APIs coming out recently from organisations, with some sort of &#8220;build it and they&#8217;ll come&#8221; expectations i.e. expecting that all they have to do is [...]]]></description>
			<content:encoded><![CDATA[<p>A little while back, I was informed that the <a href="http://www.vam.ac.uk/">V&amp;A</a> had an <a href="http://www.vam.ac.uk/api/">API</a>. To be honest, my first response to this was &#8220;why on earth?&#8221;. There&#8217;s been a few similar APIs coming out recently from organisations, with some sort of &#8220;build it and they&#8217;ll come&#8221; expectations i.e. expecting that all they have to do is provide the API and all us developers will automagically build them shiny apps for free. If you&#8217;re TfL, then this <a href="http://data.london.gov.uk/blog/tube-feed-update">kinda works</a>, but it&#8217;s not so true for a lot of places.</p>

<p>Having had this initial reaction, I still decided to dig through the documentation a bit, and spotted an interesting nugget - they&#8217;ll let you do geospatial searches. I&#8217;d been tinkering around with the idea of playing with this, especially for use with my shiny new Android phone, and I had an a idea for a little app to show you &#8220;nearby art&#8221; i.e. search with the V&amp;A&#8217;s API for the nearest bit of art.</p>

<p>I did this mostly in Javascript, doing XMLHttpRequest&#8217;s for JSON chunks of the API. There&#8217;s also a block of Python code that needs to run on a server, but that&#8217;s entirely to get around the issues of XMLHttpRequest only allowing same-server requests. It first uses navigator.geoLocation (<a href="http://dev.w3.org/geo/api/spec-source.html">official spec</a>, <a href="https://developer.mozilla.org/en/using_geolocation">easier documentation</a>) to get the user&#8217;s location, then does two V&amp;A queries - the first to get a list of local objects, and the second to get more info on the first object.</p>

<p>One thing you have to be careful about is that this can break in various ways. The most obvious is a lack of navigator.geoLocation (any version of IE, and all not-latest versions of most other browsers), and another is if the user denies access to their location data. This does make navigator.geoLocation unsuitable for general use currently, but it&#8217;s a useful source of data when there is support.</p>

<p>The full app is <a href="http://tevp.net/projects/nearby_art/">over here</a> and the source is <a href="http://github.com/palfrey/nearby_art">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/07/16/nearby-art-using-the-va-api-and-geolocation/feed</wfw:commentRss>
		</item>
		<item>
		<title>Another design sketch for Clojure coverage tool</title>
		<link>http://www.lshift.net/blog/2010/06/20/another-design-sketch-for-clojure-coverage-tool</link>
		<comments>http://www.lshift.net/blog/2010/06/20/another-design-sketch-for-clojure-coverage-tool#comments</comments>
		<pubDate>Sun, 20 Jun 2010 20:19:24 +0000</pubDate>
		<dc:creator>tim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[Clojure]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=547</guid>
		<description><![CDATA[Previously (here) I sketched out a design that went some way to being a coverage tool for Clojure code. The result was a macro that when used to define a function, resulted in an instrumented function that tallied every time the code was called. This time I am going to sketch the beginnings of a [...]]]></description>
			<content:encoded><![CDATA[<p>Previously (<a href="http://www.lshift.net/blog/2010/04/27/design-sketches-for-clojure-coverage-tool">here</a>) I sketched out a design that went some way to being a coverage tool for Clojure code. The result was a macro that when used to define a function, resulted in an instrumented function that tallied every time the code was called. This time I am going to sketch the beginnings of a design that doesn&#8217;t use a macro.</p>

<p>To start with here is a slight re-write of the structure I used last time to record the coverage:</p>

<pre>
(def coverage-records (ref nil))

(defn add-record [fn-name record]
  (dosync (alter coverage-records assoc (str fn-name) record)))

(defn get-record [fn-name]
  (get @coverage-records (str fn-name)))

(defn covering [form fn-name]
  (dosync (alter (get-record fn-name) assoc form 0)))

(defn- inc-map [map key]
  (if (contains? map key)
    (assoc (dissoc map key) key (inc (get map key)))
    map))

(defn inc-coverage [form fn-name]
  (dosync (alter (get-record fn-name) inc-map form)))
</pre>

<p>This code uses a single map to store a coverage record, another map, for each function that is being measured. Functions are provided for adding records and incrementing the coverage.</p>

<p>I am using the same set of functions to wrap and instrument the s-expressions that define the function, with a few minor modifications. I am indexing the s-expressions with a number so as to distinguish between any identical s-expressions within the function. This set of functions is still incomplete since there are lots of Clojure code that will get wrapped incorrectly, I will be rectifying this sometime in the near future.</p>

<pre>
(declare wrap-seq)
(defn wrap
  [form idx fn-name]
  (cond
    (seq? form) (
      let [key (str idx ":" form)]
        (covering key fn-name)
        (list &#8216;do `(inc-coverage ~key ~(str fn-name)) (wrap-seq form idx fn-name)))
    :else form))

(defn- indexed [coll] (map vector (iterate inc 0) coll))

(defn wrap-seq [coll count fn-name]
  (for [[idx elt] (indexed coll)] (wrap elt (+ count idx) fn-name)))
</pre>

<p>The previous article used a macro to generate Clojure code that was instrumented, this time I will load the source code for the function, wrap it and then evaluate it. This is done by the get-source function in clojure.contrib.repl-utils combined with a call to format and load-string, My code that interprets the source code is fragile and needs more work, it won&#8217;t handle functions with multiple bodies for example, but it demonstrates the principle. I am using a structure to hold the instrumented function and the coverage record for this function.</p>

<pre>
(defstruct wrapper :wrapped-fn :coverage-record)

(defn wrap-fn
  [f cv-rec]
  (let [s (read-string (get-source f))
        fn-name (first (drop 1 s))
        args (first (drop 2 s))
        body (last s)]
    (add-record fn-name cv-rec)
    (load-string (format &#8220;(fn %s %s)&#8221; args (wrap body 0 fn-name)))))

(defn wrap-function [f]
  (let [coverage-record (ref nil)]
    (struct wrapper (wrap-fn f coverage-record) coverage-record)))
</pre>

<p>So now we can try the code out at the REPL:</p>

<pre>
user=> (def x (wrap-function 'test1))   
#'user/x
user=> x
{:wrapped-fn #<user$eval__977$fn__979 user$eval__977$fn__979@1d47b2b>, :coverage-record #<Ref@3e97df: {"0:(- a b)" 0}>}
</pre>

<p>Here I have wrapped the function test1 and we can see the coverage structure returned, consisting of the wrapped function and the coverage record, keyed by the single s-expression with a count of 0. If I now use the wrapped function like this and examine the coverage structure the count should increment to 1.</p>

<pre>
user=> ((:wrapped-fn x) 1 2)            
-1
user=> x
{:wrapped-fn #<user$eval__977$fn__979 user$eval__977$fn__979@1d47b2b>, :coverage-record #<Ref@3e97df: {"0:(- a b)" 1}>}
</pre>

<p>So we now have a partially functional coverage tool and no macros have needed to be written. To complete this tool I just need to tidy up the wrapping and source code reading functions and provide some sort of binding macro so that we can call the fn with <pre>(test1 1 2)</pre> instead of <pre>((:wrapped-fn x) 1 2)</pre>. Hopefully, in my next blog entry I will have completed it! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/06/20/another-design-sketch-for-clojure-coverage-tool/feed</wfw:commentRss>
		</item>
		<item>
		<title>Little Brother: spying on yourself for fun and profit</title>
		<link>http://www.lshift.net/blog/2010/05/26/little-brother-spying-on-yourself-for-fun-and-profit</link>
		<comments>http://www.lshift.net/blog/2010/05/26/little-brother-spying-on-yourself-for-fun-and-profit#comments</comments>
		<pubDate>Wed, 26 May 2010 14:54:06 +0000</pubDate>
		<dc:creator>Tom Parker</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=545</guid>
		<description><![CDATA[One of the internal tools that some of us use is a little script called getcap. Using the venerable xwd and ImageMagick, along with a bit of shell scripting it gets run by cron 8 times an hour and dumps a screen capture into a hidden folder in your home directory. As you can imagine, [...]]]></description>
			<content:encoded><![CDATA[<p>One of the internal tools that some of us use is a little script called getcap. Using the venerable <a title="xwd" href="http://en.wikipedia.org/wiki/Xwd">xwd</a> and <a href="http://www.imagemagick.org/">ImageMagick</a>, along with a bit of shell scripting it gets run by cron 8 times an hour and dumps a screen capture into a hidden folder in your home directory. As you can imagine, this is the sort of thing that if someone else was doing it would be a nasty invasion of privacy, but if you&#8217;re doing it for yourself, it becomes invaluable for accurately filling in timesheets, especially when you&#8217;re busy juggling 3-4 different projects.</p>

<p>I&#8217;d run into a few problems with it however, primary being that xwd doesn&#8217;t play nice with compositing, and so my <a href="http://do.davebsd.com/wiki/Docky">Docky</a> instance at the top of the screen looks like a big black patch across the screenshots, which occasionally blocks useful information.</p>

<p>I&#8217;ve therefore written a replacement, called <a href="http://github.com/palfrey/LittleBrother">LittleBrother</a>, using primarily Python and gtk. Initially I was just following the instructions on the PyGtk FAQ on <a href="http://faq.pygtk.org/index.py?req=show&amp;file=faq23.036.htp">how to capture your screen</a>, but then I figured I could do a bit more. So, we now have a little status bar icon that lets you open up the screenshots folder (using <a href="http://portland.freedesktop.org/xdg-utils-1.0/xdg-open.html">xdg-open</a> so the right file manager gets used), and instead of having to hardcode in the times when you&#8217;re in the office, it instead uses the DBus interface of the Gnome screensaver (patches for other screensavers welcomed) to detect when the screensaver is active, and only take captures when it&#8217;s inactive. I found the <a href="https://fedorahosted.org/d-feet/">D-feet</a> DBus introspection tool particularly useful for playing around with this step.</p>

<p>Code is available on <a href="http://github.com/palfrey/LittleBrother">Github</a>, and there&#8217;s even a <a href="http://github.com/downloads/palfrey/LittleBrother/littlebrother_0.1-1_all.deb">Debian package</a> available as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/05/26/little-brother-spying-on-yourself-for-fun-and-profit/feed</wfw:commentRss>
		</item>
		<item>
		<title>RFC3339: Simple, canonical date parsing and formatting for Python</title>
		<link>http://www.lshift.net/blog/2010/05/20/rfc3339-simple-canonical-date-parsing-and-formatting-for-python</link>
		<comments>http://www.lshift.net/blog/2010/05/20/rfc3339-simple-canonical-date-parsing-and-formatting-for-python#comments</comments>
		<pubDate>Thu, 20 May 2010 00:43:13 +0000</pubDate>
		<dc:creator>tonyg</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=544</guid>
		<description><![CDATA[As part of a customer project some years ago, we wrote an implementation of the interesting parts of RFC 3339 for Python. The abstract for the RFC says


  This document defines a date and time format for use in Internet
  protocols that is a profile of the ISO 8601 standard for
  representation [...]]]></description>
			<content:encoded><![CDATA[<p>As part of a customer project some years ago, we wrote an <a href="http://github.com/tonyg/python-rfc3339">implementation</a> of the interesting parts of RFC <a href="http://www.ietf.org/rfc/rfc3339.txt">3339</a> for Python. The abstract for the RFC says</p>

<blockquote>
  <p>This document defines a date and time format for use in Internet
  protocols that is a profile of the ISO 8601 standard for
  representation of dates and times using the Gregorian calendar.</p>
</blockquote>

<p>We needed to be able to robustly transfer timestamps between languages (Javascript and Python, chiefly) without getting tangled up in timezone troubles or complex ambiguous parsing problems.</p>

<p>Our code provides</p>

<ul>
<li>simple, standard, robust, cross-language (e.g. Javascript) format for parsing and printing time stamps</li>
<li>a standard no-frills &#8220;UTC&#8221; <code>tzinfo</code> class and singleton instance</li>
<li>a standard no-frills fixed-offset <code>tzinfo</code> class</li>
<li>other utilities for helping write robust timezone-aware time manipulation code</li>
</ul>

<p><b>Examples</b></p>

<p>These examples are taken from the doctests/docstrings in the module source itself. See the module documentation for many more informative examples.</p>

<p>Parsing a timestamp, with timezone support and timestamp equivalence:</p>

<pre><code>&gt;&gt;&gt; midnightUTC = parse_datetime("2008-08-24T00:00:00Z")
&gt;&gt;&gt; oneamBST = parse_datetime("2008-08-24T01:00:00+01:00")
&gt;&gt;&gt; midnightUTC == oneamBST
True
</code></pre>

<p>Printing a timestamp:</p>

<pre><code>&gt;&gt;&gt; oneamBST.isoformat()
'2008-08-24T01:00:00+01:00'
&gt;&gt;&gt; parse_datetime("2008-08-24T00:00:00.123Z").isoformat()
'2008-08-24T00:00:00.123000+00:00'
</code></pre>

<p><b>Downloading the code</b></p>

<p>The code is <a href="http://github.com/tonyg/python-rfc3339/">available on github</a>. It&#8217;s <a href="http://www.opensource.org/licenses/mit-license.php">MIT-licensed</a>.</p>

<ul>
<li>Browse the code <a href="http://github.com/tonyg/python-rfc3339">here</a></li>
<li>Download a <a href="http://github.com/tonyg/python-rfc3339/tarball/master">tarball</a> of the latest code</li>
</ul>

<p>You can also install the module directly from github using <code>pip</code>:</p>

<pre><code>pip install -e git://github.com/tonyg/python-rfc3339.git#egg=rfc3339
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/05/20/rfc3339-simple-canonical-date-parsing-and-formatting-for-python/feed</wfw:commentRss>
		</item>
		<item>
		<title>A two-dimensional swingometer</title>
		<link>http://www.lshift.net/blog/2010/05/03/a-two-dimensional-swingometer</link>
		<comments>http://www.lshift.net/blog/2010/05/03/a-two-dimensional-swingometer#comments</comments>
		<pubDate>Mon, 03 May 2010 14:22:51 +0000</pubDate>
		<dc:creator>Paul Crowley</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=543</guid>
		<description><![CDATA[In addition to our swing visualizer in Java, we now have something closer to a two-dimensional swingometer in JavaScript.  Not quite as polished as I&#8217;d hoped this late, but still useful in an unpredictable election.  I hope to be updating both on election night.  Suggestions welcome!
]]></description>
			<content:encoded><![CDATA[<p>In addition to our <a href="http://dev.lshift.net/paul/election/">swing visualizer</a> in Java, we now have something closer to a <a href="http://dev.lshift.net/paul/election/swingometer/">two-dimensional swingometer</a> in JavaScript.  Not quite as polished as I&#8217;d hoped this late, but still useful in an unpredictable election.  I hope to be updating both on election night.  Suggestions welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/05/03/a-two-dimensional-swingometer/feed</wfw:commentRss>
		</item>
		<item>
		<title>Year at LShift - in photos</title>
		<link>http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos</link>
		<comments>http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos#comments</comments>
		<pubDate>Fri, 30 Apr 2010 11:26:44 +0000</pubDate>
		<dc:creator>marek</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=496</guid>
		<description><![CDATA[















































]]></description>
			<content:encoded><![CDATA[<p>
<span id="more-496"></span>

<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20081107_17-57-30/' title='20081107_17-57-30'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20081107_17-57-30-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090224_16-51-42/' title='20090224_16-51-42'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090224_16-51-42-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090225_19-33-38/' title='20090225_19-33-38'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090225_19-33-38-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090226_13-17-16/' title='20090226_13-17-16'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090226_13-17-16-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090226_14-54-36/' title='20090226_14-54-36'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090226_14-54-36-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090226_14-55-00/' title='20090226_14-55-00'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090226_14-55-00-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090226_16-46-01/' title='20090226_16-46-01'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090226_16-46-01-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090226_17-02-18/' title='20090226_17-02-18'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090226_17-02-18-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090226_17-06-27/' title='20090226_17-06-27'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090226_17-06-27-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090226_18-51-33/' title='20090226_18-51-33'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090226_18-51-33-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090227_16-46-17/' title='20090227_16-46-17'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090227_16-46-17-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090302_16-10-41/' title='20090302_16-10-41'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090302_16-10-41-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090309_23-09-27/' title='20090309_23-09-27'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090309_23-09-27-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090310_12-15-58/' title='20090310_12-15-58'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090310_12-15-58-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090310_12-16-21/' title='20090310_12-16-21'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090310_12-16-21-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090311_12-08-57/' title='20090311_12-08-57'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090311_12-08-57-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090311_12-42-21/' title='20090311_12-42-21'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090311_12-42-21-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090311_15-52-46/' title='20090311_15-52-46'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090311_15-52-46-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090311_16-22-05/' title='20090311_16-22-05'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090311_16-22-05-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090312_11-55-46/' title='20090312_11-55-46'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090312_11-55-46-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090312_18-02-45/' title='20090312_18-02-45'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090312_18-02-45-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090320_17-41-00/' title='20090320_17-41-00'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090320_17-41-00-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090320_18-09-39_1/' title='20090320_18-09-39_1'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090320_18-09-39_1-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090331_16-06-57/' title='20090331_16-06-57'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090331_16-06-57-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090403_13-29-02/' title='20090403_13-29-02'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090403_13-29-02-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090403_15-19-56/' title='20090403_15-19-56'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090403_15-19-56-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090430_14-49-45/' title='20090430_14-49-45'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090430_14-49-45-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090430_14-49-52/' title='20090430_14-49-52'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090430_14-49-52-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090501_19-55-18/' title='20090501_19-55-18'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090501_19-55-18-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090501_21-59-07/' title='20090501_21-59-07'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090501_21-59-07-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090519_17-17-54/' title='20090519_17-17-54'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090519_17-17-54-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20090605_18-15-46/' title='20090605_18-15-46'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20090605_18-15-46-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20100114_18-42-09/' title='20100114_18-42-09'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20100114_18-42-09-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20100114_19-14-09/' title='20100114_19-14-09'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20100114_19-14-09-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20100114_19-36-39/' title='20100114_19-36-39'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20100114_19-36-39-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20100114_20-04-39/' title='20100114_20-04-39'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20100114_20-04-39-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20100114_21-49-46/' title='20100114_21-49-46'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20100114_21-49-46-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20100114_21-50-47/' title='20100114_21-50-47'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20100114_21-50-47-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/20100114_22-06-48/' title='20100114_22-06-48'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/20100114_22-06-48-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/dsc_0923/' title='dsc_0923'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/dsc_0923-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/dsc_1526/' title='dsc_1526'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/dsc_1526-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/dscf0002/' title='dscf0002'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/dscf0002-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/dscf0015/' title='dscf0015'><img src="http://www.lshift.net/blog/wp-content/uploads/2010/04/dscf0015-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>

</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/04/30/year-at-lshift-in-photos/feed</wfw:commentRss>
		</item>
		<item>
		<title>Design sketches for Clojure coverage tool</title>
		<link>http://www.lshift.net/blog/2010/04/27/design-sketches-for-clojure-coverage-tool</link>
		<comments>http://www.lshift.net/blog/2010/04/27/design-sketches-for-clojure-coverage-tool#comments</comments>
		<pubDate>Tue, 27 Apr 2010 20:39:54 +0000</pubDate>
		<dc:creator>tim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=495</guid>
		<description><![CDATA[I like to write unit tests for my code and I also like to know whether my
unit tests are actually testing my code. In Java I would use Maven and
Cobertura to measure how
much of my code is actually exercised, and when I bend my mind around
Haskell I use

HPC.

I have been experimenting with Clojure and it [...]]]></description>
			<content:encoded><![CDATA[<p>I like to write unit tests for my code and I also like to know whether my
unit tests are actually testing my code. In Java I would use Maven and
<a href="http://cobertura.sourceforge.net/">Cobertura</a> to measure how
much of my code is actually exercised, and when I bend my mind around
Haskell I use
<a href="http://www.haskell.org/ghc/docs/latest/html/users_guide/hpc.html">
HPC</a>.</p>

<p>I have been experimenting with Clojure and it has a nice testing library
but the only way I have found to measure coverage is to use Cobertura
and squint at the generated class names to work out what I haven&#8217;t covered.
So I have started on the road to creating a coverage tool for Clojure
written in Clojure. This blog entry contains my initial steps and
design sketches towards creating the tool.</p>

<p>Ideally I&#8217;d like to measure my coverage like this:</p>

<pre>(ns some.tests
  (:use [some.functions])
  (:use [coverage.cover])
    (:use [clojure.test]))

(deftest test-something
    (cover &#8216;(foo bar)                   ; cover foo and bar
      (is (= [1 2 3] (foo 1 2 3)))
        (is (= [2 4 6] (bar 1 2 3)))

        (is (= [100 100] (coverage foo))) ; check coverage
        (is (= [100 100] (coverage bar)))

        (store-coverage)))                ; store report to file</pre>

<p>That isn&#8217;t functional code yet and may not be what I finally produce, it
might not even be valid Clojure since I haven&#8217;t even bashed it into a REPL
yet.</p>

<p>As Clojure is a Lisp, and we are testing our own code - i.e. we have the
source code - we should be able to measure the coverage using Clojure. This
can achieved by rebinding the functions under test with instrumented functions;
this is what I envisage the cover function is doing:</p>

<pre>(cover '(foo)
  ; all calls to foo here actually call foo'
)</pre>

<p>Which can be achieved using a binding function:</p>

<pre>(binding [a b)]
    ; all calls to a here are actually calls to b
)</pre>

<p>So assuming I can write the cover function I will need to instrument
a function. Let&#8217;s start simply and ignore the complicated stuff such
as conditional statements and multiple bodies until later. If we have
this simple function</p>

<pre>(defn foo [a b c] (+ a (- b c)))</pre>

<p>I would like an instrumented version to wrap each s-expression with
a function that records that the s-expression has been called, for
now we will just print a message.</p>

<pre>(defn foo-wrapped [a b c]
  (do
      (prn :wrap)
        (+ a
          (do
            (prn :wrap)
              (- b c)))))</pre>

<p>Testing that in the REPL seems to reveal that I am moving in the right
direction:</p>

<pre>user=&gt; (foo 1 2 3)
0
user=&gt; (foo-wrapped 1 2 3)
:wrap
:wrap
0
user=&gt;</pre>

<p>To convert the first function to the instrumented function I need a couple
of auxiliary functions and a macro:</p>

<pre>(defn record [] (prn :wrap))

(declare wrap-seq)
(defn wrap [form]
  (cond
      (seq? form)
          (list &#8216;do (record) (wrap-seq form))
        :else form))

(defn wrap-seq [xs]
  (for [x xs] (wrap x)))

(defmacro cover
  [args &amp; body]
    (let [fn-name (when (symbol? args) args)
          args (if fn-name (first body) args)
                body (if fn-name (next body) body)]
      (fn ~@(if fn-name (list fn-name args) (list args))
          ~@(wrap (first body)))))</pre>

<p>If you know some Clojure that code demonstrates some of the problems I haven&#8217;t
solved yet when measuring coverage, for example the :else clause will need
to be covered as well as functions in binding statements. Testing that code
in the REPL gives us a reasonable result:</p>

<pre>user=&gt; (def x (cover [a b c d] (+ a (- b c (* a d)))))
#&#8217;user/x
user=&gt; (x 1 2 3 4)
:wrap
:wrap
:wrap
-4
user=&gt;</pre>

<p>So if I now replace the record function with something else I may be able
to generate some coverage for a function. I am going to use a map held by
a ref to store the coverage information, a function to register a particular
s-expression with the ref and a function to increment the count.</p>

<pre>(def coverage-records (ref nil))

(defn covering [form]
  (dosync (alter coverage-records assoc form 0)))

(defn- inc-map [map key]
  (if (contains? map key)
    (assoc (dissoc map key) key (inc (get map key)))
    map))

(defn inc-coverage [key]
  (dosync (alter coverage-records inc-map key)))</pre>

<p>Lets test that:</p>

<pre>user=&gt; @coverage-records
nil
user=&gt; (covering :x)
{:x 0}
user=&gt; (covering :y)
{:y 0, :x 0}
user=&gt; (inc-coverage :x)
{:x 1, :y 0}
user=&gt; (inc-coverage :y)
{:y 1, :x 1}
user=&gt; (inc-coverage :x)
{:x 2, :y 1}
user=&gt; @coverage-records
{:x 2, :y 1}
user=&gt;</pre>

<p>If I modify our wrapping functions I can create the coverage records ready to
be incremented.</p>

<pre>(defn wrap [form]
  (cond
    (seq? form) (do
      (covering (str form))
      (list &#8216;do `(record) (wrap-seq form)))
    :else form))</pre>

<p>Testing that code:</p>

<pre>user=&gt; (def x (cover [a b c d] (+ a (- b c (* a d)))))
#&#8217;user/x
user=&gt; @coverage-records
{&#8221;(* a d)&#8221; 0, &#8220;(- b c (* a d))&#8221; 0, &#8220;(+ a (- b c (* a d)))&#8221; 0}
user=&gt;</pre>

<p>And that is as far as I have got. I need to change my record function
to increment the coverage records, make my wrap function cope with
conditionals and other complexities and write my rebinding function.
Hopefully next month I will have moved it along a little bit further.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/04/27/design-sketches-for-clojure-coverage-tool/feed</wfw:commentRss>
		</item>
		<item>
		<title>SpringSource / VMWare Acquire Rabbit Technologies</title>
		<link>http://www.lshift.net/blog/2010/04/14/springsource-vmware-acquire-rabbit-technologies</link>
		<comments>http://www.lshift.net/blog/2010/04/14/springsource-vmware-acquire-rabbit-technologies#comments</comments>
		<pubDate>Wed, 14 Apr 2010 13:05:28 +0000</pubDate>
		<dc:creator>mike</dc:creator>
		
		<category><![CDATA[Erlang]]></category>

		<category><![CDATA[RabbitMQ]]></category>

		<category><![CDATA[Technology]]></category>

		<category><![CDATA[LShift]]></category>

		<category><![CDATA[open source]]></category>

		<category><![CDATA[SpringSource]]></category>

		<category><![CDATA[VMWare]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=493</guid>
		<description><![CDATA[SpringSource, a division of VMware, Inc. today announced the acquisition by VMware of Rabbit Technologies, Ltd, a company set up by LShift and partners Monadic and CohesiveFT.

Read the full story
]]></description>
			<content:encoded><![CDATA[<p>SpringSource, a division of VMware, Inc. today announced the acquisition by VMware of Rabbit Technologies, Ltd, a company set up by LShift and partners Monadic and CohesiveFT.</p>

<p><a href="http://www.lshift.net/news/rabbitmqacquired.html">Read the full story</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/04/14/springsource-vmware-acquire-rabbit-technologies/feed</wfw:commentRss>
		</item>
		<item>
		<title>Debian build-depends metapackages</title>
		<link>http://www.lshift.net/blog/2010/04/12/debian-build-depends-metapackages</link>
		<comments>http://www.lshift.net/blog/2010/04/12/debian-build-depends-metapackages#comments</comments>
		<pubDate>Mon, 12 Apr 2010 14:49:17 +0000</pubDate>
		<dc:creator>Tom Parker</dc:creator>
		
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=492</guid>
		<description><![CDATA[When I&#8217;m doing development on an existing software project, and especially when I&#8217;m trying to bugfix something with a Debian package, I find that I install random packages I need to rebuild something, and then later on I&#8217;m wondering why I&#8217;ve got those installed. I tend to try to keep with the philosophy that the bits [...]]]></description>
			<content:encoded><![CDATA[<p>When I&#8217;m doing development on an existing software project, and especially when I&#8217;m trying to bugfix something with a Debian package, I find that I install random packages I need to rebuild something, and then later on I&#8217;m wondering why I&#8217;ve got those installed. I tend to try to keep with the philosophy that the bits of software I&#8217;m using are pretty knowledgeable about whatever they&#8217;re intended to do, and so trusting them to make smart decisions is a good idea. For package managers, this means I should only keep track of the software that I actually use, and tell the package manager that everything else has been automatically installed and can therefore be removed when they cease to be a dependency of something I actually need. Having packages that I only installed for building something else without a record of that in the package management system breaks that mental model.</p>

<p>Enter <a href="http://github.com/palfrey/dh-builddep-metapackage">dh-builddep-metapackage</a> (the naming is inline with the names used by the <a href="http://man.he.net/man7/debhelper">debhelper</a> scripts used for other debian packaging stuff).  dh-builddep-metapackage builds build-dependency metapackages in order to ease package
management for package rebuilders. In effect, it builds a &#8220;&lt;package name&gt;-builddep&#8221; package that has no content, but depends on everything that the existing package build-depends on. By using dh-builddep-metapackage to create metapackages rather than using &#8220;apt-get build-dep&#8221;, I keep a record in the package management about why I need a particular development package, and can remove the dependant packages when I&#8217;m no longer working with the relevant source package.</p>

<p>I think someone&#8217;s done this before, but some work with Google didn&#8217;t find it, and it was an interesting exercise anyway. Standard usage is &#8220;dh-builddep-metapackage -b &lt;package name&gt;&#8221;, which will create the metapackage data and build the package for you using dpkg-buildpackage. A folder called &#8220;&lt;package name&gt;-&lt;package version&gt;&#8221; will be created in the current local directory, and if an existing folder exists then dh-builddep-metapackage will refuse to overwrite it (unless you give the -o/&#8211;overwrite option).</p>

<p>So far I&#8217;ve used it a few times, and it&#8217;s quite nice to have those packages around to remind me about the dependencies. I&#8217;m considering building a full repository with *-builddep packages for everything in the Debian archives, but I&#8217;d like to make sure I&#8217;d use this enough first.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2010/04/12/debian-build-depends-metapackages/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
