<?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>Graceful Exits &#187; formats</title>
	<atom:link href="http://www.jpstacey.info/blog/category/formats/www.jpstacey.info/blog/category/formats/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jpstacey.info/blog</link>
	<description>Garbage collection, in a very real sense</description>
	<pubDate>Thu, 14 Aug 2008 09:05:55 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Firefox/Sage bookmarks to Google Reader import</title>
		<link>http://www.jpstacey.info/blog/2008/07/17/firefoxsage-bookmarks-to-google-reader-import/</link>
		<comments>http://www.jpstacey.info/blog/2008/07/17/firefoxsage-bookmarks-to-google-reader-import/#comments</comments>
		<pubDate>Thu, 17 Jul 2008 19:04:54 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[formats]]></category>

		<category><![CDATA[import/export]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=186</guid>
		<description><![CDATA[When OPML is OPML but it isn't OPML]]></description>
			<content:encoded><![CDATA[<p>Want to migrate your RSS bookmarks from Firefox (or its RSS-reading addon, Sage) to Google Reader? I did, just now.</p>
<p>Christopher Hinze has written a great <a href="https://addons.mozilla.org/en-US/firefox/addon/2625" >Firefox addon that exports bookmarks to OPML 1.0</a>. Unfortunately, OPML is a bit of an <a href="http://www.opml.org/spec1" >anything-goes specification</a>. So although Hinze&#8217;s plugin produces valid OPML, it isn&#8217;t the same sort of valid OPML that Google Reader expects. Google Reader, in fact, gags and chokes on Hinze&#8217;s OPML, and refuses to import it.</p>
<p>The main problem is that the &lt;outline/&gt; element, the basic hierarchical building block for OPML, <a href="http://www.opml.org/spec1#limits" >will take <em>any attributes</em></a>. What does that mean in practice? Well, here&#8217;s what Hinze&#8217;s export produces:</p>
<blockquote class="code"><p>
&lt;outline text=&#8221;Coding&#8221;><br />
&nbsp;&nbsp;&lt;outline type=&#8221;link&#8221; text=&#8221;Joel on Software&#8221; url=&#8221;http://www.joelonsoftware.com/rss.xml&#8221;   /><br />
&lt;/outline>
</p></blockquote>
<p>and here&#8217;s the result of Google Reader exporting its own store of RSS bookmarks:</p>
<blockquote class="code"><p>
&lt;outline title=&#8221;Coding&#8221; text=&#8221;Coding&#8221;><br />
&nbsp;&nbsp;&lt;outline text=&#8221;drupal.org - Community plumbing&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp;title=&#8221;drupal.org - Community plumbing&#8221; type=&#8221;rss&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp;xmlUrl=&#8221;http://drupal.org/node/feed&#8221; htmlUrl=&#8221;http://drupal.org&#8221;/><br />
&lt;/outline>
</p></blockquote>
<p>To a computer, these are fundamentally two different data formats: the URLs are stored in different attributes, and there are attributes on each that either have different values or are not present on the other. Someone did a <a href="http://static.userland.com/gems/radiodiscuss/opmlDtd.txt" >DTD for OPML</a>: looking at those two apparently analogous fragments above you have to ask yourself why they bothered.</p>
<p>Help is at hand, though. This sort of problem is bread and butter to XSLT, and <a href="/applications/google/ff2gr_opml.xsl" >here&#8217;s an XSL transform for converting Firefox OPML to Google Reader OPML</a>. If you have <code>xsltproc</code> installed on your system, you would type:</p>
<blockquote class="code"><p>
xsltproc http://www.jpstacey.info/applications/google/ff2gr_opml.xsl bookmarks.opml > fixed_bookmarks.opml
</p></blockquote>
<p>Or download the XSLT&#8212;it&#8217;s released under GPL2&#8212;and run it locally, changing that URL there to a local file location.</p>
<p>One thing to note: the XSLT will remove an outline wrapped around your bookmarks with title &#8220;Sage Feeds&#8221; (case-sensitive). So you can export that branch of your bookmarks, and the XSLT will strip the wrapper off and you <em>won&#8217;t</em> import a load of bookmarks tagged &#8220;Sage Feeds&#8221;. If you don&#8217;t like this behaviour then either rename your Sage bookmark container, or learn XSLT: it won&#8217;t kill you.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/07/17/firefoxsage-bookmarks-to-google-reader-import/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Cheaper rail journeys with Matthew and Spliticket</title>
		<link>http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/</link>
		<comments>http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/#comments</comments>
		<pubDate>Thu, 13 Mar 2008 21:39:28 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[formats]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/</guid>
		<description><![CDATA[I&#8217;ve built something, just in time for me to crowbar it awkwardly into conversations at OKCon.
Matthew Somerville is well known for his accessible takes on rubbish websites: most useful is Traintimes, a layer on top of one of the equally poor commercial British rail sites; most notorious is Accessible Odeon, a fixing of the Odeon [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve built something, just in time for me to crowbar it awkwardly into conversations at OKCon.</p>
<p>Matthew Somerville is well known for his accessible takes on rubbish websites: most useful is <a href="http://traintimes.org.uk/">Traintimes</a>, a layer on top of one of the equally poor commercial British rail sites; most notorious is <a href="http://www.dracos.co.uk/odeon/" >Accessible Odeon</a>, a fixing of the Odeon Cinema&#8217;s website that put their own substandard development to shame so much that in 2004 they had Matthew&#8217;s version taken down with legal threats. Remember: just because you&#8217;re successful doesn&#8217;t mean you&#8217;re not stupid.</p>
<p>Recently, Matthew gave an <a href="http://oxford.geeknights.net/" ><abbr title="Oxford Geek Nights">OGN</abbr></a> <a href="http://oxford.geeknights.net/2007/july-25th/talks/MatthewSomerville.mp4" title="'Train in Vain' by Matthew Somerville (mp4 video)">talk on split tickets</a>. These are train journeys which one cross-country train company sells at exhorbitant rates, whereas the components of the journey can be bought separately from the local companies for considerably less. This is what we infer; the rail websites try to keep it all quiet, in the hope that you might lose interest and stump up. The whole headshakeworthy situation is either a stinging indictment of the stupidity of privatizing a rail network and making passengers jump through ridiculous hoops to glean even the tiniest advantage, or a perfect demonstration of how the choice-enriched consumer can leverage capitalism in action: take your pick. </p>
<p>To come to the point: Matthew has set up a wiki where people have been adding the <a href="http://www.dracos.co.uk/wiki/Trains/SplitTickets" >split tickets they&#8217;ve worked out</a> in an <i>ad-hoc</i> fashion. Last Sunday I added K&#8217;s astonishing 47% saving for Oxford&#8211;Cardiff to the end of it, and there&#8217;s been little activity since. The page hasn&#8217;t got fantastic Google juice&#8212;&#8221;split tickets&#8221; means too many other things&#8212;and is just non-dynamic HTML, editable through the wiki but otherwise searchable only by eye.</p>
<p>At the moment, of course, there&#8217;s no reason for Matthew to expend any more effort on such a small and barely popular data set. But last Sunday I had a sudden instinctive jolt, to the effect that: more people would be likely to take advantage of split tickets if there was an easier way of looking up other people&#8217;s discoveries (my colleagues were recently trying to find split tickets and the wiki page was harder to use than Traintimes, for that very purpose).</p>
<p>With this in mind, here&#8217;s my take on accessificating the wiki page: <a href="http://www.jpstacey.info/applications/spliticket/">Spliticket</a>. It accesses a cached version of the page, and then using Python&#8217;s HTMLParser to hack away at the HTML it returns either a HTML or XML representation of any journey it finds. The idea is that it&#8217;s a bit easier to use on your mobile device, and lets you pin down journeys better. I&#8217;ve also included an option for searching strictly for the same journey: I&#8217;m not sure if split tickets&#8212;even returns&#8212;always work when the journey is reversed.</p>
<p>Spliticket also supports friendly URLs (inspired by Traintimes itself), so York to Edinburgh in HTML becomes &lt;<a href="http://www.jpstacey.info/applications/spliticket/html/york/edinburgh/" >http://www.jpstacey.info/applications/spliticket/html/york/edinburgh/</a>&gt; and the aforementioned Oxford to Cardiff route in XML becomes: &lt;<a href="http://www.jpstacey.info/applications/spliticket/xml/oxford/cardiff/">http://www.jpstacey.info/applications/spliticket/xml/oxford/cardiff/</a>&gt; .</p>
<p>Mostly this was just something to fill idle hours, and also to convince myself of some ideas I&#8217;ve had recently about loose coupling, data reuse and open data. Hopefully at the same time (a) Matthew won&#8217;t take it as a dig, (b) others might find some casual use for it see it, and (c) a select few might see it as a testament to the ease of freeing information from solid if unsemantic markup. And maybe in six months&#8217; time we&#8217;ll all be booking split tickets as a matter of course; by then, of course, Spliticket will probably be gratefully obsolete, replaced by the fully-fledged application that poor, embittered rail passengers deserve. I&#8217;m sure Matthew will build it if so.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/feed/</wfw:commentRss>
<enclosure url="http://oxford.geeknights.net/2007/july-25th/talks/MatthewSomerville.mp4" length="15044283" type="video/mp4" />
		</item>
		<item>
		<title>Last.fm on Ubuntu Gutsy: smooth as rabbit fur</title>
		<link>http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/</link>
		<comments>http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/#comments</comments>
		<pubDate>Sun, 03 Feb 2008 18:28:33 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[business]]></category>

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

		<category><![CDATA[non-programming]]></category>

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

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

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

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

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

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

		<category><![CDATA[climate change]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/</guid>
		<description><![CDATA[One of my resolutions this year is to try to cut down on the carbon I spend on music. Notwithstanding my purchase of the In Rainbows discbox, I&#8217;ve amassed an awful number of discs of metallized plastic in barely-recyclable containers. (I say &#8220;barely&#8221; because K. got me a pencil for Christmas made out of old [...]]]></description>
			<content:encoded><![CDATA[<p>One of my resolutions this year is to try to cut down on the carbon I spend on music. Notwithstanding <a href="/blog/2007/12/10/working-out-chaotic-things/">my purchase of the <cite>In Rainbows</cite> discbox</a>, I&#8217;ve amassed an awful number of discs of metallized plastic in barely-recyclable containers. (I say &#8220;barely&#8221; because K. got me a pencil for Christmas made out of old CD boxes, and a pen from dead car parts. But there&#8217;s only so many pencils the world can use.) </p>
<p>As I spend the scraps and offcuts of January and February evenings ripping and filing my 2007&#8217;s CDs&#8212;some of which I won&#8217;t listen to very often once they&#8217;re fossilized in the collection&#8212;I&#8217;m aware of a tremendous weight of <em>madeness</em> and invested time and energy on the part of the manufacturers, and of a sort of casual luxuriating in my first-world lifestyle on my own part. <i>You prepare a playlist before me in the presence of my enemies. You anoint my tapeheads with crude oil; my CD tray overflows.</i> So in 2008 I hope to buy as few CDs as possible (none is the target) while also avoiding DRM-crippled music and staying legal.</p>
<p>To this end I&#8217;ve been seeking free and semi-free online music&#8212;free as in beer, semi-free as in of limited choice&#8212;since the new year. So far, outside of bittorrenting (which is obviously of variable legality, depending on what you&#8217;re downloading), I&#8217;m having some success with <a href="http://last.fm/">Last.fm</a>. Until recently they offered a sort of customized &#8220;radio station&#8221;, where your input into the of the next track was limited to an intelligent deduction by Last.fm based on what you told it you enjoyed in the past. Now, alongside this potluck service, they&#8217;ve just started offering <a href="http://www.pcadvisor.co.uk/news/index.cfm?RSS&#38;NewsID=11947">three free streamings of any explicitly chosen track</a> before requiring you to buy the track from  a commercial partner.</p>
<p>I&#8217;ve yet to try the former service (I think you might have to subscribe to be on the beta wagon: I&#8217;ll look into that later), but the latter has so far provided our house with unlimited, free access to a radio station for our very own target market. While such slightly sinister profiling might make it harder for me to discover <em>truly</em> new music, it does at least permit me to expand the boundaries of my comfort zone slowly, and cast a critical eye over my friends&#8217; music preferences, while at the same time giving artists their due and most importantly avoiding physical recordings unless I really want them.</p>
<p>Most commercial support for Linux distributions still consists of monolithic installations, wrapped up with checksums to prevent you tampering with them, and installing themselves on your computer in whatever location and potentially harmful fashion they fancy. Until upgrading to Gutsy this was largely my experience (painfully and often repeated) with such packages as nVidia and wireless drivers, and interesting software that barely gave a second thought to existing Feisty users. </p>
<p>After a spot of Googling I was expecting to have to go through <a href="http://rolandog.com/archives/2006/07/27/lastfm-linux-client-available/">the same palaver with Last.fm&#8217;s client</a>, and crossed my fingers that nothing would go horribly wrong. But I needn&#8217;t have worried: the Linux client for Last.fm is</p>
<ol type="A">
<li>free of cost, as in beer</li>
<li>free of restrictions, as in open source</li>
<li>free of hard work, as in a no-sweat installation utilizing the Debian packages and apt package management that&#8217;s core to Ubuntu</li>
</ol>
<p>To install it on Gutsy, you first want to add the GPG key for the repository for security reasons. At a command line, type:</p>
<blockquote class="code"><p>wget -q http://apt.last.fm/last.fm.repo.gpg -O- | sudo apt-key add -</p>
</blockquote>
<p>You&#8217;ll be asked by <code>sudo</code> for your password. Then, open Synaptic Package Manager (under &#8220;System &gt; Administration&#8221; in the GNOME menus); then, via &#8220;Settings &gt; Repositories&#8221;, add the following new third-party repository:</p>
<blockquote class="code"><p>deb http://apt.last.fm/ debian stable</p>
</blockquote>
<p>You can then search for the Last.fm widget&#8217;s package in the manager (hint: it&#8217;s called lastfm) and install it. When you first run it after installation it&#8217;ll ask for your Last.fm account, so best have one of those in advance. And that&#8217;s it: you&#8217;ve now got Last.fm&#8217;s widget on your Ubuntu PC.</p>
<p>All of the above is explained briefly on <a href="http://apt.last.fm/">the very URL of the apt repository</a>. Not only that, but they have a free bonus photo of a very cute bunny in case all the apt stuff bores you rigid. Like a TV licence for the <a href="http://www.bbc.co.uk/iplayer">Flash version of the BBC iPlayer</a>, all of this is practically worth a subscription alone. As I type, my mouse sits over the very location of the link to do so in a separate tab. I just need to know first: how many more rabbits do I get when I join?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Library of Congress, Flickr&#8217;d to the max</title>
		<link>http://www.jpstacey.info/blog/2008/01/17/library-of-congress-flickrd-to-the-max/</link>
		<comments>http://www.jpstacey.info/blog/2008/01/17/library-of-congress-flickrd-to-the-max/#comments</comments>
		<pubDate>Thu, 17 Jan 2008 10:43:22 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[culture]]></category>

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

		<category><![CDATA[import/export]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/01/17/library-of-congress-flickrd-to-the-max/</guid>
		<description><![CDATA[Flickr is working with the Library of Congress on new project The Commons. Currently there are around three thousand photographs up there from two collections, and according to the Commons homepage they&#8217;re all copyright-free. More information in the relevant post on the Flickr blog.
This is wonderful news, especially because the collection is being released through [...]]]></description>
			<content:encoded><![CDATA[<p>Flickr is working with the Library of Congress on new project <a href="http://flickr.com/commons">The Commons</a>. Currently there are around <strong>three thousand</strong> photographs up there from two collections, and according to the Commons homepage they&#8217;re all copyright-free. More information in <a href="http://blog.flickr.com/en/2008/01/16/many-hands-make-light-work/">the relevant post on the Flickr blog</a>.</p>
<p>This is wonderful news, especially because the collection is being released through a slightly adapted version of Flickr&#8217;s existing website. This means, apart from it being an established interface that millions of people already know vaguely how to use, that you can do all the Flickry things with the photos&#8212;dedicated Flickr-heads will hopefully give a more qualified response in due course&#8212;and that third-party tools should already be set up to work with the content. The meta information storage won&#8217;t particularly excite any Dublin-Core enthusiasts&#8212;a block of unstructured HTML in the standard Flickr notes field, plus of course Flickr tagging&#8212;but the whole project is still a fascinating experiment, and interesting for even the casual observer of American history. How exciting does it get? More exciting than the <a href="http://www.flickr.com/photos/library_of_congress/2179047088/in/set-72157603671370361/">World of Mirth Shows</a>?</p>
<p>Thinking offline for a moment, this hopefully presages more leaps forward in <abbr title="Museums, Libraries and Archives">MLA</abbr> culture. One of the first would be to remove the &#8220;NO PHOTOGRAPHS&#8221; signs from all museums. At the very least such signs could be more honest, and instead read &#8220;NO PHOTOGRAPHS; unless our security guards don&#8217;t catch you at it, in which case we&#8217;ll be blissful in our ignorance. Anyway, in five years time it&#8217;ll all be online so we don&#8217;t know why we&#8217;re bothering, to be honest&#8230;.&#8221; On reflection, I suppose they would need bigger signs.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/01/17/library-of-congress-flickrd-to-the-max/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Distributed FM radio from a single digital signal</title>
		<link>http://www.jpstacey.info/blog/2007/11/25/distributed-fm-radio-from-a-single-digital-signal/</link>
		<comments>http://www.jpstacey.info/blog/2007/11/25/distributed-fm-radio-from-a-single-digital-signal/#comments</comments>
		<pubDate>Sun, 25 Nov 2007 14:57:48 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[configuration]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/11/25/distributed-fm-radio-from-a-single-digital-signal/</guid>
		<description><![CDATA[There&#8217;s currently no plan to switch off FM stations. In fact, many radio bosses have said oh, for heaven&#8217;s sake to the very idea. There is, astonishingly, less of a plan for radio switchover than there is desire among the general public for TV switchover. So that must be some sort of record for nothingness.
Seriously: [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s currently <a href="http://www.frequencycast.co.uk/godigital.html">no plan to switch off FM stations</a>. In fact, many radio bosses have said <a href="http://www.guardian.co.uk/media/2004/jul/08/radio">oh, for heaven&#8217;s sake</a> to the very idea. There is, astonishingly, less of a plan for radio switchover than there is desire among the general public for TV switchover. So that must be some sort of record for nothingness.</p>
<p>Seriously: who among us is just itchy and fidgety, waiting for analogue TV signals to be switched off? Who wakes up of a morning thinking, ooh, Whitehaven have to buy Freeview boxes now! with a frisson of glee? Radio switchover would be even more disastrous, of course: whereas TVs normally have a gap between themselves and an aerial into which to insert a Freeview box and convert digital to analogue, most radios are monolithic: receiver, &#8220;decoder&#8221; and audio equipment all together. That means that the average of five radios per household would be simply landfill material, useless fizzing boxes capable of picking up nothing but static. Future generations will already find a sliver in the geological strata that they can classify as &#8220;analogue to digital&#8221;; FM switchoff would add a shiny, plasticky laminate to that layer.</p>
<p>Here&#8217;s a thought, though: how about a little digital-to-analogue converter for radio? It could be the size and construction of, say, a <a href="http://www.fon.com/">Fon</a>, and configurable over USB. It would transmit FM in the style of an <a href="http://en.wikipedia.org/wiki/ITrip">iTrip</a> to fill perhaps the room it&#8217;s kept in, plus neighbouring rooms. It could transmit multiple FM stations at the same time, and even mimic the frequencies of the analogue stations (if they were ever, say, switched off without anyone wanting them to be: God forbid!)</p>
<p>But what if your converter&#8217;s chosen frequencies conflict with next door? FM transmission depends on phase coherence, so even if your two boxes were within an electronic ace of each other frequency-wise, they&#8217;d still interfere with each other and cause all sorts of beating, flangeing and other dirtily-named auditory confusion. At least when someone passes you on the motorway and their phat BMW iPod transmitter briefly swamps yours then they&#8217;re gone quickly, hopefully to come to some sort of messy grief on the next bend. But if you&#8217;re stuck near someone who permanently foxes your radio listening&#8212;and it would only take maybe three or four such converters for a conflict to be inevitable in the narrow FM band&#8212;then what do you do?</p>
<p>Answer: <em>let the converter boxes know how to talk to each other</em>. Let them negotiate their frequency spreads. Let them, moreover, report back to you over what sort of understandings you and your neighbour&#8217;s radios can come to. Let them synchronize, if possible, on stations you both want to listen to, strengthening the signal and meaning both of your houses are entirely covered by the FM cloud. Exploit, don&#8217;t squash, the wisdom of the group.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/11/25/distributed-fm-radio-from-a-single-digital-signal/feed/</wfw:commentRss>
		</item>
		<item>
		<title>OpenOffice arrows, .soe files and writing your own SVG</title>
		<link>http://www.jpstacey.info/blog/2007/08/01/openoffice-arrows-soe-files-and-writing-your-own-svg/</link>
		<comments>http://www.jpstacey.info/blog/2007/08/01/openoffice-arrows-soe-files-and-writing-your-own-svg/#comments</comments>
		<pubDate>Wed, 01 Aug 2007 13:48:44 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[formats]]></category>

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

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

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

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

		<category><![CDATA[many-to-one]]></category>

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

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

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

		<category><![CDATA[svg:d]]></category>

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/08/01/openoffice-arrows-soe-files-and-writing-your-own-svg/</guid>
		<description><![CDATA[Creating your own arrows in OpenOffice (.org, 2.0) is a pain. There&#8217;s tutorials out there that claim to show how to create arrows from OOo diagrams, but I&#8217;ve not had much success with those. However, by taking apart an existing arrow, I&#8217;ve managed to work out the rather nasty syntax
OOo arrow libraries are suffixed .soe, [...]]]></description>
			<content:encoded><![CDATA[<p>Creating your own arrows in OpenOffice (.org, 2.0) is a pain. There&#8217;s tutorials out there that claim to show <a href="http://openoffice.blogs.com/openoffice/2005/11/applying_and_cr.html">how to create arrows from OOo diagrams</a>, but I&#8217;ve not had much success with those. However, by taking apart an existing arrow, I&#8217;ve managed to work out the rather nasty syntax</p>
<p>OOo arrow libraries are suffixed .soe, and just contain plain-text XML for a full library (so multiple arrows are defined in one file, and only one library can be loaded at once). These libraries sit in your user-specific config directory: to find out where that is, right-click on a line and go to &#8220;Line&#8230;&#8221;, then click on the &#8220;Arrow Styles&#8221; tab and find the little folder icon for loading new libraries. Click on that, and see where your file explorer puts you.</p>
<p>Arguably it&#8217;s easier to either add to or replicate an existing .soe file: the structure is simple enough but there are a lot of namespaces to get right. So open a copy of one of the existing files and have a look inside. It should be structured something like the following:</p>
<blockquote class="code"><p>
&lt;?xml version=&#8221;1.0&#8243; ?&gt;<br />
&lt;office:marker-table <i>&#8230; xmlns declarations&#8230;</i> &gt;<br />
&nbsp;&nbsp;&lt;draw:marker<br />
&nbsp;&nbsp;&nbsp;&nbsp;draw:name=&#8221;Arrow name&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp;svg:viewBox=&#8221;<i>x1 y1 x2 y2</i>&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp;svg:d=&#8221;<i>mess of semi-numerical data</i>&#8221; /&gt;<br />
&nbsp;&nbsp;&lt;draw:marker <i>&#8230;</i> /&gt;<br />
&nbsp;&nbsp;&lt;draw:marker <i>&#8230;</i> /&gt;<br />
&lt;/office:marker-table&gt;
</p>
</blockquote>
<p>The mess of data up there is the kicker: it looks a bit like SVG path data, but not quite. The reason is that the spacing is often all over the place, so whilst <a href="http://www.w3.org/TR/SVG11/paths.html#PathDataMovetoCommands">SVG path commands</a> are usually of the form <code>XN</code>, where <code>X</code> is a letter and <code>N</code> a cursor position or a length, OOo frequently seems to prefix commands with numbers. This is actually just an artifact of the format: put spaces in after any number that doesn&#8217;t have them, and it reads as a sane SVG path.</p>
<p>So the structure of the arrow can be constructed using the basic, etch-a-sketchy SVG commands, with the following provisos:</p>
<ul>
<li>Whitespace is irrelevant (see above)</li>
<li>OpenOffice <em>always</em> deals with closed paths. If your path isn&#8217;t closed with a terminating <code>z</code> SVG command, OpenOffice will do so for you. It will then <em>fill in</em> this closed path with the line colour! The tutorial above gives you ways of avoiding this, but I think it&#8217;s a consequence of SVG not having a native understanding of line width.</li>
<li>OpenOffice has a creative understanding of the standard SVG directions &#8220;V&#8221; and &#8220;H&#8221;</li>
<li>The SVG viewbox parameter is probably best left alone: I think it&#8217;s similar to the bounding box on postscript files, creating a window for the vector graphic to sit in.</li>
</ul>
<p>An example is worth a thousand words, even if that example is made up of a thousand hard-to-read SVG commands, so here we go. The image below is a schematic of a three-pronged many-to-one arrow I want to use. The arrow line continues up the page from the junction of the three prongs.</p>
<div class="image image-centre">
<img src="http://www.jpstacey.info/blog/wp-content/uploads/2007/08/oo2_svg_arrow_cropped.gif" alt="OpenOffice many-to-one arrow" />
</div>
<p>As you can see, when the parent line is running horizontally (as it appears in the OOo configuration, H actually describes movement along the vertical. With this in mind, the entry for this arrow would read:</p>
<blockquote class="code"><p>
&lt;draw:marker<br />
&nbsp;&nbsp;draw:name=&#8221;Arrow name&#8221;<br />
&nbsp;&nbsp;svg:viewBox=&#8221;<i>x1 y1 x2 y2</i>&#8221;<br />
&nbsp;&nbsp;svg:d=&#8221;m1000 1162<br />
&nbsp;&nbsp;&nbsp;&nbsp;l 0 -125 -125 0 -859 859<br />
&nbsp;&nbsp;&nbsp;&nbsp;v-859<br />
&nbsp;&nbsp;&nbsp;&nbsp;h-176<br />
&nbsp;&nbsp;&nbsp;&nbsp;v859<br />
&nbsp;&nbsp;&nbsp;&nbsp;l -859-859 -125 0 0 125 859 859 213 213<br />
&nbsp;&nbsp;&nbsp;&nbsp;z&#8221; /&gt;
</p>
</blockquote>
<ol>
<li>[M]ove the cursor to an x/y position to start (this makes the arrow start at the end of the line)</li>
<li>[L]ine: draw towards -v, -h, then along a diagonal</li>
<li>[V]ertical line towards -v, [h]orizontal towards -h, [v]ertical towards +v</li>
<li>[L]ine: draw a diagonal, then towards -h and +v, then two diagonals in the same direction</li>
<li>Clo[z]e the drawing</li>
</ol>
<p>And that&#8217;s it. Fairly simple, as long as you break down your design into SVG primitives first, and realise how OOo is working. There&#8217;s some refinements that, as I&#8217;ve reverse-engineered much of this, I&#8217;ve not been able to go into: the starting position seems to only partly affect the arrow, as it gets centred on the line regardless; the viewbox seems to get ignored. But if anyone can take this any further, than do let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/08/01/openoffice-arrows-soe-files-and-writing-your-own-svg/feed/</wfw:commentRss>
		</item>
		<item>
		<title>CFJavaXML - a component for cached XML transformations</title>
		<link>http://www.jpstacey.info/blog/2007/02/09/cfjavaxml-a-component-for-cached-xml-transformations/</link>
		<comments>http://www.jpstacey.info/blog/2007/02/09/cfjavaxml-a-component-for-cached-xml-transformations/#comments</comments>
		<pubDate>Fri, 09 Feb 2007 16:34:46 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[formats]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/02/09/cfjavaxml-a-component-for-cached-xml-transformations/</guid>
		<description><![CDATA[Mark Mandel wrote his own version of Coldfusion&#8217;s XmlTransform() function, using the underlying Java transform classes. Although one of his annoyances&#x2014;that XmlTransform() won&#8217;t take any parameters&#x2014;has been solved in CFMX7, XmlTransform() is nonetheless a slow operation, as the transform engine has to be cranked up, the XSL compiled, the transform effected and then everything garbage-collected, [...]]]></description>
			<content:encoded><![CDATA[<p>Mark Mandel wrote his own <a href="http://www.compoundtheory.com/?action=displayCategory&#38;ID=4" title="Reasons I hate XMLTransform()">version of Coldfusion&#8217;s XmlTransform() function</a>, using the underlying Java transform classes. Although one of his annoyances&#x2014;that XmlTransform() won&#8217;t take any parameters&#x2014;has been solved in CFMX7, XmlTransform() is nonetheless a slow operation, as the transform engine has to be cranked up, the XSL compiled, the transform effected and then everything garbage-collected, each call to the function, each request.</p>
<p>To improve Coldfusion for dedicated XSL programmers, I&#8217;ve turned Mark&#8217;s one-off function into a more granular <a href="/blog/files/code/cfjavaxml.tgz" title="Download CFJavaXML as a .tgz file">component for cacheable, Java-based XSL transformations, called CFJavaXML</a>. You can cache this component from request to request in a persisting scope. You can also compile an XSL transformation once, then store that in a persisting scope too and re-use it without having to keep accessing the XSL file (and compiling it, which can take time). It&#8217;ll bring in all its xsl:import references at compilation too, so you needn&#8217;t worry about having to keep track of your XSL directory from transformation to transformation.</p>
<p>The component needs no initialization, so create it as follows:</p>
<blockquote class="code"><p>
&lt;cfset comp_cfjx = createObject(&#8221;component&#8221;, &#8220;#PATH_TO_COMPONENTS#.cfjavaxml&#8221;)&gt;
</p>
</blockquote>
<p>You can cache this in a persisting scope at this point. </p>
<p>Using CFJavaXML is always a two-stage process, so that you get a compiled transformation object you can store and re-use. In the following example, <code>XSL</code> and <code>XML</code> can be either local <code>file://(/)</code> references, <code>http://</code> URLs or even strings of valid XML:</p>
<blockquote class="code"><p>
&lt;script&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;t = comp_cfjx.XslTextToTransformer( XSL );<br />
&nbsp;&nbsp;&nbsp;&nbsp;xmltext = comp_cfjx.XmlTransformFromTextAndJava( XML, t [, params]);<br />
&lt;script&gt;
</p>
</blockquote>
<p>(The transform <code>t</code> is the compiled transform that you can cache from request to request.) Note also where any optional parameters can be inserted, using a <code>params</code> struct.</p>
<p>Depending on the transformation (and how many times you use it) the speed increase of using CFJavaXML has been quite striking: up to ten times with certain transformations. Benchmarking is quite difficult because it depends so much on the intricacy of the XSL: your mileage may vary.</p>
<p>(Thanks to my employers, <a href="http://www.torchbox.com/">Torchbox</a>, who&#8217;ve given me permission to make this code available, and thanks to Mark for showing how to do it in the first place!)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/02/09/cfjavaxml-a-component-for-cached-xml-transformations/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Realplayer to mp3: a configurable Python wrapper</title>
		<link>http://www.jpstacey.info/blog/2006/12/06/realplayer-to-mp3-a-configurable-python-wrapper/</link>
		<comments>http://www.jpstacey.info/blog/2006/12/06/realplayer-to-mp3-a-configurable-python-wrapper/#comments</comments>
		<pubDate>Wed, 06 Dec 2006 20:55:14 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[configuration]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2006/12/06/realplayer-to-mp3-a-configurable-python-wrapper/</guid>
		<description><![CDATA[It&#8217;s one of the worst-kept tech secrets in the world, but Real Audio streams can be downloaded using software such as mplayer and then converted to MP3 format with lame. Both of these are available in Ubuntu using the non-Ubuntu package manager Automatix. The possibility of doing this conversion implies that, although the BBC offer [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s one of the worst-kept tech secrets in the world, but Real Audio streams can be downloaded using software such as <code>mplayer</code> and then converted to MP3 format with <code>lame</code>. Both of these are available in Ubuntu using the non-Ubuntu package manager <a href="http://www.getautomatix.com/">Automatix</a>. The possibility of doing this conversion implies that, although the BBC offer all their programs in Real Audio and only a few as podcasts, you can in principle put any you like on your portable music device.</p>
<p>Similar solutions abound on the web: Tom Taylor has <a title="How to rip BBC radio streams to MP3" href="http://www.tomtaylor.co.uk/blog/2006/09/01/how-to-rip-bbc-radio-streams-to-mp3/">a method involving <code>mencoder</code></a>; other methods can be found <a title="Convert Real Audio to mp3" href="http://www.macosxhints.com/article.php?story=20050130184054216">all over the place</a>. However, these all involve a bit of <i>ad hoc</i> command-line intervention, or scripts which aren&#8217;t terribly configurable. There are GUI and proprietary commands, but they tend not to offer great support for command-line and therefore scheduled operation.</p>
<p>I&#8217;ve knocked together a Python application called <code>rmrip</code>: it&#8217;s available in a tar file from <a href="http://www.jpstacey.info/blog/files/code/rmrip.tgz">http://www.jpstacey.info/blog/files/code/rmrip.tgz</a>. If you unzip this to a directory you&#8217;ll find a number of <code>.py</code> files and a <code>config.conf</code> configuration file. Edit <code>config.conf</code> to match your system requirements and stream preferences, make sure <code>rmrip.py</code> is executable, then run it. mp3s should eventually appear in a subdirectory called YYYYMMDD unless you configure the system otherwise.</p>
<p>The application can in principle be run from a cronjob, so it could tick over late at night when everyone&#8217;s internet is otherwise nice and quiet. In addition, conversion works via a <a href="">named pipe</a>, which is a funky way of piping the intermediary, enormous <code>.wav</code> audio file straight into <code>lame</code>, rather than saving it to disk. This does unfortunately restrict the application to non-Windows machines, but it&#8217;s a great help for audiophiles with limited disk space: <code>.ra</code> and <code>.mp3</code> files can be in the hundreds of megabytes for many-hour programmes, but the associated <code>.wav</code> would take up gigabytes.</p>
<p>Current requirements include (please give any feedback on this!):</p>
<ul>
<li><code>mplayer</code> and <code>lame</code>: their locations are configurable</li>
<li>The <code>subprocess</code> module in Python</li>
</ul>
<p>Current file types supported:</p>
<ul>
<li>Direct rtsp://&#8230;.ra Real Audio stream links</li>
<li>http://&#8230;.ram references to Real Audio streams</li>
<li>http://&#8230;.rpm Real Audio playlists (BBC so far only format tested)</li>
</ul>
<p>To get you started, <a href="http://dave.org.uk/">dave.org.uk</a> has provided information on <a href="http://dave.org.uk/streams">how to get stream information</a> using a standalone Python program, and also has potentially out-of-date static pages detailing the current BBC streams.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2006/12/06/realplayer-to-mp3-a-configurable-python-wrapper/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Blosxom to WordPress: tying up loose ends</title>
		<link>http://www.jpstacey.info/blog/2006/11/06/blosxom-to-wordpress-tying-up-loose-ends/</link>
		<comments>http://www.jpstacey.info/blog/2006/11/06/blosxom-to-wordpress-tying-up-loose-ends/#comments</comments>
		<pubDate>Mon, 06 Nov 2006 10:56:36 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[formats]]></category>

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

		<category><![CDATA[import/export]]></category>

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2006/11/06/blosxom-to-wordpress-tying-up-loose-ends/</guid>
		<description><![CDATA[A busy few weeks, but they&#8217;ve included an import from a Blosxom blog to a WordPress blog which is worth describing. There are a couple of established methods for importing the data, and I opted for the one that seemed the most modular. This was Eric Davis&#8217; Import-Blosxom method, consisting of a PHP script on [...]]]></description>
			<content:encoded><![CDATA[<p>A busy few weeks, but they&#8217;ve included an import from a Blosxom blog to a WordPress blog which is worth describing. There are a <a href="http://codex.wordpress.org/Importing_Content#Blosxom" title="Blosxom">couple of established methods</a> for importing the data, and I opted for the one that seemed the most modular. This was <a href="http://www.insanum.com/">Eric Davis&#8217;</a> <a href="http://www.insanum.com/downloads/Wordpress/import-blosxom.php.gz">Import-Blosxom</a> method, consisting of a PHP script on the WordPress side and a set of Blosxom flavour files which produce a feed compatible with RSS 2.0. This separation of Blosxom and WordPress behaviours meant that I could thoroughly test the former before proceeding with the latter.</p>
<p>It worked very well with practically no configuration or edits, but there were a few issues with the out-of-the-box behaviour of the import script:</p>
<ol>
<li>Unicode character entities were being escaped in titles, leading to the exposure of the alphanumeric code e.g. &#8220;Z&amp;amp;#252;rich&#8221; instead of &#8220;Z&#252;rich&#8221;.</li>
<li>Whitespace in post bodies is converted to hard newlines by WordPress, and so must be excised to avoid tags being broken e.g. &#8216;&lt;a [newline] href=&#8221;&#8230;&#8221;&gt;&#8217; becoming &#8216;&lt;a &lt;br/&gt; href=&#8221;&#8230;&#8221;&gt;&#8217;.
  </li>
<li>Multiple hierarchical categories are not supported (a known problem).</li>
<li>Although categories are created and posts are linked to them, the number of posts that a category is used in is not incremented and hence the list of categories on the front-end has zero posts for each category(possibly owing to a change between WordPress versions of how this has been handled).</li>
</ol>
<p>I&#8217;ve come up with a number of fixes that I&#8217;ve mentioned both to Davis and <a href="http://wordpress.org/support/topic/32515" title="Migrating from Blosxom">on the WordPress support forums</a>. As they&#8217;ve been greeted with an eerie silence that I&#8217;ve found typical of such forums, I&#8217;ll put them up here instead.</p>
<p>To fix the first three problems I created <a title="a Blosxom plugin to fix a number of RSS2.0-to-WordPress issues" href="/blog/files/code/blosxom/rss_to_wp">rss_to_wp</a>, a Blosxom plugin that, along with the standard <code>interpolate_fancy</code> package, you can use to wrap your title and category processing bits in the RSS2.0 flavour templates. Respectively, this plugin tackles the above problems by:</p>
<ol>
<li>Providing an <code>interpolate_fancy</code> method to unescape entities</li>
<li>Normalizing any whitespace in the body of your Blosxom posts to single spaces</li>
<li>Providing an <code>interpolate_fancy</code> method to convert a Blosxom-style category path into a set of category tags</li>
</ol>
<p>You&#8217;ll need to change the Davis-recommended <code>story.rss20</code> template to implement the two interpolation methods. I&#8217;ve made a <a title="Blosxom story flavour for RSS 2.0" href="/blog/files/code/blosxom/story.rss20">sample</a> available.</p>
<p>The final issue was a more knotty problem, as it was a bug in the script (possibly caused by WordPress&#8217; handling of categories changing over time). It&#8217;s easily fixed by adding a few lines to the category-handling part of <code>import-blosxom.php</code> as follows:</p>
<blockquote class="code"><pre>
294    if (!$exists)
295    {
296        $wpdb-&gt;query("INSERT INTO $wpdb-&gt;post2cat (post_id, category_id)
297                      VALUES ($post_id, $cat_id)");
298    }
299
300    // JPS' addition - increment count if cat ID exists
301    if ($cat_id) {
302        $wpdb-&gt;query("UPDATE $wpdb-&gt;categories SET category_count = category_count + 1 WHERE cat_ID = $cat_id");
303    }
304    // End JPS' addition
</pre>
</blockquote>
<p><b>Exit gracefully:</b> exporting and then importing&#x2014;<i>trans</i>porting?&#x2014;works well if the two tasks are separable. That way the integrity of the exported data can be checked in its transitory state and any bugs worked out, before it&#8217;s imported into the new system. It&#8217;s certainly worthwhile backing up the target database for the import, as this lets you preserve any quirks of your target database if you have to dump all the imported data and start again. The standard WordPress install includes a plugin for doing this, but the command-line tool <a href="http://del.icio.us/jp.stacey/mysql+backup+restore+command-line" title="J-P Stacey's del.icio.us bookmarks for MySQL backup/restore">mysqldump</a> is arguably more powerful.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2006/11/06/blosxom-to-wordpress-tying-up-loose-ends/feed/</wfw:commentRss>
		</item>
		<item>
		<title>How to write a Javascript file</title>
		<link>http://www.jpstacey.info/blog/2006/10/03/how-to-write-a-javascript-file/</link>
		<comments>http://www.jpstacey.info/blog/2006/10/03/how-to-write-a-javascript-file/#comments</comments>
		<pubDate>Tue, 03 Oct 2006 08:53:01 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[formats]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2006/10/03/how-to-write-a-javascript-file/</guid>
		<description><![CDATA[Now I know the title sounds presumptuous, but there&#8217;s a certain methodology I&#8217;ve settled into that seems to work really well for encouraging Javascript that&#8217;s legible and safe. I thought I&#8217;d share it with anyone that doesn&#8217;t consider themselves a JS playa, in case it&#8217;s of some use to you too. 
Most Javascript libraries these [...]]]></description>
			<content:encoded><![CDATA[<p>Now I know the title sounds presumptuous, but there&#8217;s a certain methodology I&#8217;ve settled into that seems to work really well for encouraging Javascript that&#8217;s legible and safe. I thought I&#8217;d share it with anyone that doesn&#8217;t consider themselves a <em>JS playa</em>, in case it&#8217;s of some use to you too. </p>
<p>Most Javascript libraries these days are written in a similar way, so it seems to be <i>de facto</i> recognised best practice, but it&#8217;s worth showing the anatomy of the simple case so you can build on it rather than having to work out what&#8217;s going on from an enormous, somewhat crufty sprawl.</p>
<blockquote class="code"><p>
/*<br />
&nbsp;&nbsp;&nbsp;&nbsp;@description Javascript template<br />
&nbsp;&nbsp;&nbsp;&nbsp;@createdBy JPS<br />
&nbsp;&nbsp;&nbsp;&nbsp;@createdOn 2006-10-03<br />
&nbsp;&nbsp;&nbsp;&nbsp;@notes Standard template<br />
*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
MyObjectWithHandyName = {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Properties<br />
&nbsp;&nbsp;&nbsp;&nbsp;p: {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// HTML IDs<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i: { },<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// HTML classes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c: { },<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Something else we might need to reference<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sthg: {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Be wary of accidental trailing commas here, as it&#8217;s the end of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// the array and IE doesn&#8217;t like a comma at that position<br />
&nbsp;&nbsp;&nbsp;&nbsp;},<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Methods here - use hierarchy if large object<br />
&nbsp;&nbsp;&nbsp;&nbsp;DOM: {},<br />
&nbsp;&nbsp;&nbsp;&nbsp;eyeCandy: {  dropdowns: {}, errors: {} },<br />
&nbsp;&nbsp;&nbsp;&nbsp;httpReq: {},<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Window onload method - instantiates everything<br />
&nbsp;&nbsp;&nbsp;&nbsp;go: function() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&#8217;OK!&#8217;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
};<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
// Now add onload handler to do anything your object needs to do when page loads<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
// Prototype<br />
// Event.observe(window, &#8216;onload&#8217;, MyObjectWithHandyName.go, false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
// Mochikit &#38; others<br />
// addLoadEvent(MyObjectWithHandyName.go);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
// No library?<br />
window.onload = MyObjectWithHandyName.go;
</p>
</blockquote>
<p>What&#8217;re the advantages of the above? Well, first of all, it just formalizes what you&#8217;ve already decided to do: that is, to encapsulate all the functionality to do with a certain <em>something</em> in one file. This just puts it all in one object, which you could call <code>DHTML</code>, or <code>iFoo</code>, or <code>GoogleHack</code>, or <code>MyApp</code>. It prevents collisions with standard Javascript functions, library functions you might include etc. Also, if in future you want to know if a function has been defined on a page, but from a different Javascript file, it&#8217;s sufficient for a smallish project to check the top-level object exists. </p>
<p>Secondly, the system is very extensible, and tidy with it. If configuration variables go in the hierarchical <code>p</code>(roperties) block at the top of the file, then you can re-use your code by, say, including a second Javascript file on certain pages, that rewrites this configuration. You can even change methods like this, if you know where they&#8217;re going to be, in a safe, extensible way. The hierarchy of the whole object means you can nest methods as far down as you want: then, if you find yourself repeating much of the hierarchy, you can use the <code>with(object)</code> control structure to tidy your code:</p>
<blockquote class="code"><p>
foo: { bar: { quux: { a: function() {&#8230;}, b: function() {&#8230;} } } },<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
blort: {<br />
&nbsp;&nbsp;&nbsp;&nbsp;with(foo.bar.quux) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a(b(a()));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;foo.bar.quux.a();<br />
}
</p>
</blockquote>
<p>Thirdly, it&#8217;s easy to maintain. Encapsulation and a certain predictability, and the encouragement to make methods small and put them somewhere that makes sense rather than build e.g. sprawling validation methods that, oh, do a bit of browser sniffing as well, and a bit of <code>alert()</code> calling&#8230; this definitely forces me to be careful in what I write, and that puts me in a good position to fix things later on.</p>
<p>I can&#8217;t say I&#8217;ve done any serious testing, but this way of building functionality seems far more robust, and exits more gracefully (on most decent browsers), than other paradigms for Javascript design. It&#8217;s possible this is how the whole Javascript community is now coding and I&#8217;m teaching my grannies to suck eggs: certainly it&#8217;s not how you&#8217;d code given ten minutes on Google, so it probably bears repeating.</p>
<p>A few caveats, of course, because there is no silver bullet:</p>
<ul>
<li>All function definitions go in <code>MyObjectWithHandyName</code>: nothing outside that apart from the onload to do any actual function <em>calls</em>.</li>
<li>Any text used more than once (URLs, HTML classes, alert text, repalcement text etc.) goes in <code>p</code> at the top of the script.</li>
<li>Any event handlers should be wary of what they get as their first parameter, and what the <code>this</code> object refers to: depending on how they get called, that might change from event to element to their hierarchical container in <code>MyObjectWithHandyName</code>.</li>
<li>Trailing commas: at the end of an associative array, don&#8217;t leave a trailing comma as Firefox will quietly ignore it but IE will give one of its typically opaque syntax errors.</li>
<li>Similarly, don&#8217;t omit commas between elements&#x2014;<code>{ a: {} b: {} }</code> is wrong&#x2014;as all browsers will die. Easily done, if you&#8217;re writing a new method and you forget the <code>go()</code> already exists.</li>
</ul>
<p>Anyway, give it a go and see what you think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2006/10/03/how-to-write-a-javascript-file/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
