<?xml version="1.0"  encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="http://thingsinjars.com/includes/style/rss.css" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<atom:link href="http://thingsinjars.com/rss/home/" rel="self" type="application/rss+xml" />
<title>Things in Jars</title>
<link>http://thingsinjars.com/</link>
<description>Articles from Things in Jars</description>
<language>en</language>
<docs>http://en.wikipedia.org/wiki/RSS_(file_format)</docs>
<lastBuildDate>Tue, 07 Feb 12 00:00:00 -0800</lastBuildDate>
<ttl>45</ttl><item>
<title>JS Minification is seriously addictive.</title>
<link>http://thingsinjars.com/post/452/js-minification-is-seriously-addictive/</link>
<guid>http://thingsinjars.com/post/452/js-minification-is-seriously-addictive/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-452">
        <p><a href="http://thingsinjars.com/post/452/js-minification-is-seriously-addictive/">JS Minification is seriously addictive.</a></p>
<p>Having gotten hooked on it during the first <a href="http://js1k.com/">js1k</a>, written about <a href="http://thingsinjars.com/post/293/the-quest-for-extreme-javascript-minification/">extreme JS minification</a> and submitted a bunch of stuff to <a href="http://140byt.es/users/thingsinjars">140bytes</a>, I think it's fairly safe to say I'm an addict. Because of that, there was really no chance that I could let this year's js1k go by without entering.</p>

<p>The theme this year is &lsquo;<a href="http://js1k.com/2012-love/">Love</a>&rsquo;. Seeing as I never actually submitted my <a href="http://thingsinjars.com/post/296/maze-1k/">maze1k</a> demo, I decided I'd spruce it up, restyle a bit and submit it covered top to bottom in hearts. </p>

<p>There's not a lot I can say about minification techniques that hasn't already been covered either on <a href="http://thingsinjars.com/post/293/the-quest-for-extreme-javascript-minification/">this</a> <a href="http://thingsinjars.com/post/296/maze-1k/">site</a>, on <a href="http://marijnhaverbeke.nl/js1k/">Marijn Haverbeke's site</a>, on <a href="http://benalman.com/news/2010/08/organ1k-js1k-contest-entry/">Ben Alman's</a> or on the <a href="https://github.com/jed/140bytes/wiki/Byte-saving-techniques">140bytes wiki page on byte-saving techniques</a>. The only things I will add are a couple of techniques which are new to me. I have thoroughly commented the code below, however. If you want to play along, have a look.</p> 

<h2>Left-first Evaluation</h2>
<p>It's a feature of most programming languages that when you have a logical operator such as <code>&amp;&amp;</code> or <code>||</code>, the value of the left side of the operator determines whether the right side will be evaluated at all. If the left side of an AND is false, we're going to get a false for the whole thing. It doesn't matter what the right side is so we don't even need to look at it. Similarly, if the left side of an OR is true, the eventual return value will be true so we don't need to look at the right. For example, here are two statements:</p>

<pre><code>coffee&amp;&amp;morning
wine||work
</code></pre>

<p>In the first example (<code>&amp;&amp; &ndash; AND</code>), we will <em>only</em> check <code>morning</code> if <code>coffee</code> is true. We first have a look at <code>coffee</code> and if it is false, we don't care whether morning is true or not, we just skip it (and, presumably, go back to bed). If <code>coffee</code> is <code>true</code>, we'll then have a look to see if morning is true. It doesn't matter if morning is a function or a variable assignment or whatever, it will only happen if <code>coffee</code> is true.</p>
<p>In the second example (<code>|| &ndash; OR</code>), we will only evaluate <code>work</code> if <code>wine</code> is false. We start by looking at and evaluating <code>wine</code>. If that is true, the JS interpreter saves us from even considering <code>work</code> and skips it. The right-side of the operator, <code>work</code>, is only considered if wine is false.</p>
<p>You can probably see how, in a few simple situations, this can help avoid an <code>if()</code>, thereby saving at least one byte. Usually.</p>

<h2>&lsquo;A&rsquo; font</h2>
<p>If you want to set the font-size on a canvas 2D context, you have to use the font property. Makes sense, right? Unfortunately for obsessive minifiers, you can't <em>just</em> set the fontSize, you also have to set the fontFamily at the same time:</p>
<pre><code>canvas.getContext('2d').font="20px Arial"</code></pre>
<p>Failure to set the font family means that the whole value is invalid and the font size isn't applied.</p>

<p>My thought process: &ldquo;But 'Arial'? The word's so&hellip; big (5 bytes). There must be some way to make this smaller. If only there were a font called &lsquo;A&rsquo; (1 byte)&hellip;&rdquo;</p>

<p>Well, it turns out, if you set a font that doesn't exist on the user's system, the canvas will fall back on the system sans-serif by default. On windows that is... Arial. On OS X, it's Helvetica. I'm glad about that because otherwise, Helvetica wouldn't get a look-in, being 9 whole bytes.</p>
<p>There is always the chance that someone will have a font called &lsquo;A&rsquo; but I'm willing to take that risk. This possibility could be avoided by using an unlikely character like &#9829; for the font name.</p>

<h2>The code</h2>
<p>These are hosted on <a href="https://gist.github.com/1740736">GitHub</a> rather than in my usual code blocks to make it easier for you to fork them, pull them apart and get elbow-deep in them.</p>
<h3>The almost-impossible-to-read minified submission:</h3>

<h3>The full, unminified code with thorough commenting:</h3>



<h2>The submission</h2>
<p>My entry is up on the <a href="http://js1k.com/2012-love/demo/1028">js1k site now</a>. It's already getting quite busy up there after only a few days and I have to say I'm impressed by the fantastic job <a href="https://twitter.com/#!/kuvos">@kuvos</a> has done in building it up over the last couple of years and providing me with fuel for my addiction.</p>      </div>
]]></description>
<pubDate>Tue, 07 Feb 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>ImpressJS Tools</title>
<link>http://thingsinjars.com/post/448/impressjs-tools/</link>
<guid>http://thingsinjars.com/post/448/impressjs-tools/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-448">
        <p><a href="http://thingsinjars.com/post/448/impressjs-tools/">ImpressJS Tools</a></p>
<p>While putting together last week's <a href="http://thingsinjars.com/post/446/museum140-shorty/">promo video for Museum140</a> (a vote'd be awsm, btw), I knocked up a few tools to make my life easier. As I always say, if you find something you like, make a plugin for it. Seriously, I <strong>always</strong> say that. That might even be how I proposed to my wife, I'll have to check.</p>

<p>Anyway.</p>

<h2>Play</h2>
<p>This is a simple timing helper. It just provides a little array you can push slide durations into and at the end, you call 'play'. I can't see many uses for this other than in creating videos.</p>
<pre><code>ImpressJS.play(3000);  //Set the first slide duration for 3 seconds
ImpressJS.play(1000);  //Set the second slide duration for 1 second
ImpressJS.play(); //Play from the start
</code></pre>

<h2>Edit</h2>
<p>This is much more useful.</p>

<p>If this script is included in the page (after the impress.js script), you can drag your slides around, rotate and scale them into exactly the position you want. Once you're happy, you can get the current HTML output onto the console for pasting back into your original slideshow file. I could have snuck in a <a href="http://thingsinjars.com/post/440/create-a-draggable-file-on-the-fly-with-js/">drag-n-drop file handler</a> but that would make it Chrome only.</p>


<h2>Disclaimer</h2>
<p>These tools rely on ImpressJS having a public API which it currently doesn't have. It's obviously high on the author's priority list (given the <a href="https://github.com/bartaz/impress.js/issues/39">amount of discussion</a> it's raised) but, as too many pull requests spoil the broth, I've made a <a href="https://github.com/thingsinjars/impress.js">little fork of my own</a>, added the public functions the tools require and I'll update them once the main repository's settled down a bit.</p>

<h2>Download</h2>
<p>These are available in the tools folder of this <a href="https://github.com/thingsinjars/impress.js">fork of impress.js</a>. Each one contains an example. Hopefully, these will be updated to use the public API as soon as it's available.</p>
      </div>
]]></description>
<pubDate>Mon, 16 Jan 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Museum140 Shorty</title>
<link>http://thingsinjars.com/post/446/museum140-shorty/</link>
<guid>http://thingsinjars.com/post/446/museum140-shorty/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-446">
        <p><a href="http://thingsinjars.com/post/446/museum140-shorty/">Museum140 Shorty</a></p>
<p>As regular readers are probably aware, one of my side projects is helping out <a href="http://www.museum140.com">Museum140</a> with tech and design support (<a href="http://thingsinjars.com/post/378/archiving-tweets/">building websites</a>, <a href="http://jennifuchs.tumblr.com/post/13250126051/museum140-goodies">designing stickers</a>, etc). <a href="https://twitter.com/#!/jennifuchs">Jenni's</a> the main driving force behind some of the coolest &ldquo;Museums and Social Media&rdquo; projects of the past year. </p>

<p>The Museum140 project is <a href="http://shortyawards.com/museum140?category=museum">in the running for a Shorty Award</a> so I thought I'd help out by making a promo video. Of course, it's always best to play to your strengths so I built the video as a web page&hellip;</p>

<h2>ImpressJS</h2>
<p>HTML5 slideshows are all pretty cool (I even <a href="http://thingsinjars.com/widgets/html5-presentation/#/">used one myself</a> a few months back) but most of them deliberately emulate traditional slide presentations. When I saw <a href="https://github.com/bartaz/impress.js">ImpressJS</a> for the first time last week, I was astounded. Its <a href="http://bartaz.github.com/impress.js/#/">style</a> is based on <a href="http://prezi.com/">prezi.com</a> but built using CSS3 rather than Flash. As well as being an inventive way of giving presentations, it also gave me an idea. </p>

<p>A couple of hours coding later and we've got a simple but stylish video with every word and phrase positioned perfectly. I wrote a little helper function to assist in creating a consistent timeline and recorded it in <a href="http://www.telestream.net/screen-flow/">Screenflow</a>. After that, I spent 10 minutes with the other kind of keyboard and came out with a nice little piece of background music, too. </p>

<h2>The Video</h2>


<p>There you go, ImpressJS is not only good for slideshow but also promo videos. Not bad.</p>

<h2>Vote?</h2>
<p>It would also be remiss of me if I didn't ask those of you with a twitter account to at least consider <a href="http://shortyawards.com/museum140?category=museum">voting</a>.</p>      </div>
]]></description>
<pubDate>Tue, 10 Jan 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Umpteen ways to test for a function</title>
<link>http://thingsinjars.com/post/445/umpteen-ways-to-test-for-a-function/</link>
<guid>http://thingsinjars.com/post/445/umpteen-ways-to-test-for-a-function/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-445">
        <p><a href="http://thingsinjars.com/post/445/umpteen-ways-to-test-for-a-function/">Umpteen ways to test for a function</a></p>
<p>After wrestling with another <a href="http://140byt.es/" title="140byt.es">140bytes</a> challenge, I found myself wondering how many different ways you can test an object in JS to see if it&rsquo;s a function. I wrote out a few of them then threw it out to my colleagues who came up with a few more. I&rsquo;d love to hear from anyone who can suggest more to add to the list. Ideally, you want to find a test that will return true for all functions and only for functions. It&rsquo;d be great if it&rsquo;s a universal test that can be slightly modified to test for other types but that&rsquo;s not essential.</p>

<p><strong>Bear in mind, most of these shouldn&rsquo;t be used in the real world, this is just for fun.</strong></p> 

<p>There are a couple of main categories and several variations within.</p>

<h2>Duck Typing</h2>
<p>When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.</p><a href="http://en.wikipedia.org/wiki/Duck_test">The Duck Test</a>
<p>In other words, if an object has the methods of a function and the properties of a function, it&rsquo;s probably a duck. No, that doesn&rsquo;t sound right.</p>
<p>This simply detects whether the object we&rsquo;re testing contains the methods or properties we&rsquo;d normally associate with a function. The most common test is checking whether <code>a.call</code> exists. In most cases, this will only be defined on a function and it will be defined on all functions. It is, therefore, a good test to use.</p>

<p>The downside is that it can be fooled by setting a property of call on the object to be truthy. This will pass the test but still not be a function. Also, if the object is null or undefined, this will throw a TypeError (as pointed out by <a href="https://gist.github.com/1466219#gistcomment-71121">subzey on git</a>).</p>

<pre><code>a.call                   // Hey, this has a call property. Quack?
a.call &amp;&amp; a.call.call    // The call also has a call so is probably also a function. Quack.
a.apply                  // As before but with apply this time
a.apply &amp;&amp; a.apply.apply // ditto and ditto
</code></pre>

<h2>String comparisons on typeof</h2>
<p>This area of inspection is probably the richest for coming up with silly ideas to test. The <code>typeof</code> operator simply returns a string containing the type of the object. That&rsquo;s it. Anything you can think of to compare a string against another string, be it RegEx, charAt, equals or threequals (===) can be manipulated to become a check for type.</p>
<pre><code>typeof a>'f'&amp;&amp;typeof a&lt;'g'   // Long-winded and quite silly. Performs a numerical comparison on the strings
(typeof a).charAt(0)=='f'    // Sturdy but not very useful.
typeof a==typeof eval        // May as well use eval for something, it&rsquo;s a global function
typeof a==typeof dir         // Shorter but might not exist everywhere
typeof a=='function'         // The usual way to test. Everything above here is purely academic
/^f/.test(typeof a)          // Matching the string against a unique RegEx. See the table below
typeof a==typeof b           // Requires access to another variable which is a known function
(typeof a)[0]=='f'           // Small and robust but doesn&rsquo;t work in IE6 or 7
</code></pre>

<h3>Table of RegEx Patterns to match object types:</h3>
<p>As little aside here, we&rsquo;ve got a table of simple RegEx tests that do the same as the one mentioned above. They return true if the type is what you expect, false for all other types. They work by assuming things like &lsquo;object&rsquo; being the only type to contain a &lsquo;j&rsquo; or &lsquo;boolean&rsquo; being the only one with an &lsquo;a&rsquo;.</p>
<pre><code>Type         RegEx                 Note
boolean      /a/.test(typeof a)    // Shorter than typeof a==&lsquo;boolean&rsquo;
function     /^f/.test(typeof a)   // Shorter than typeof a==&lsquo;function&rsquo;
undefined    /d/.test(typeof a)    // Shorter than typeof a==&lsquo;undefined&rsquo;
number       /m/.test(typeof a)    // Same length as typeof a==&lsquo;number&rsquo;
object       /j/.test(typeof a)    // Same length as typeof a==&lsquo;object&rsquo;
string       /s/.test(typeof a)    // Same length as typeof a==&lsquo;string&rsquo;
null         /ll/.test(typeof a)   // Longer than typeof a==&lsquo;null&rsquo;
</code></pre>

<h2>Pick &amp; Mix</h2>
<p>This not only makes the assumption that an object is probably a function if it contains a &lsquo;call&rsquo; but also that if that call has the same type as the object, they&rsquo;re both probably functions.</p>
<pre><code>typeof a==typeof a.call      // A mixture of typeof string comparison and duck typing</code></pre>

<h2>instanceof</h2>
<p>In some circumstances, <code>instanceof</code> is going to be better than typeof as it compares types rather than strings.</p>
<pre><code>a instanceof Function      // This will throw a ReferenceError if a is undefined.</code></pre>

<h2>The [[Class]] of the object</h2>
<p>This comes from the <a href="http://bonsaiden.github.com/JavaScript-Garden/#types.typeof" title="typeof at JavaScript Garden">JavaScript Garden</a> where you&rsquo;ll find they have a strong opinion on <code>typeof</code> and <code>instanceof</code>. This uses <code>call</code> to execute the <code>toString</code> method on the <code>prototype</code> of the basic <code>Object</code> constructor. Phew. At that point, you'd have a string &lsquo;<code>[Object Function]</code>&rsquo;. You can then chop off the beginning and the end using slice (treating the string as if it were an array) to get just the type. All together, it looks like this:</p>
<pre><code>Object.prototype.toString.call(a).slice(8, -1);</code></pre>

<h2>Testing the string representation of the object</h2>
<p>This is fairly nasty but still quite effective. Convert the object itself to a string (not its type but the actual object) and see if that begins with &lsquo;function&rsquo;. This is nowhere nearly as robust as some of the other tests as this will also pass true for any strings that begin "function..." but it&rsquo;s quite cunning. Credit goes to <a href="http://twitter.com/mmarcon">Max</a> for this one.</p>
<pre><code>/^function/.test(a.toString())   //Test if the output of .toString() begins with &lsquo;function&rsquo;
/^function/.test(a+"")           //As above but using a shortcut to coerce the function to a string.
</code></pre>

<h2>Running it</h2>
<p>This isn&rsquo;t so much checking whether it looks and sounds like a duck, this is more like serving it <em>&agrave; l&rsquo;orange</em> and seeing if it tastes like a duck. The idea here is to actually try and execute it. If it throws an error, it&rsquo;s not executable, if it doesn&rsquo;t, it is. Or something like that. Here, we&rsquo;re testing that the error is an <code>instanceof</code> TypeError as an undefined object would also end up in the catch.</p>
<p>The obvious downfall to this technique is that you don&rsquo;t necessarily want the function executed when you&rsquo;re testing it. In fact, you almost never want to do that. I might go as far as to say you <strong>never</strong> want that.</p>
<pre><code>try {
  a();
  true;
} catch (e) {
  !(e instanceof TypeError);
}
</code></pre>
<p>The other big weakness in the above technique is that, even if the object is a function, the call itself might throw a TypeError. In Chrome, there's a bit more transparency as the error thrown has a type property. In that case you want to check that the type is <code>'called_non_callable'</code> but that might still be a consequence of the function. In Safari, there's a similar property on the error (<code>e.message</code>) but the error object itself is no longer a TypeError, it is just an Error.</p>

<h2>More&hellip;</h2>
<p>I&rsquo;m certain there are more. Many, many more. There are also several dozen that are trivial variations on those mentioned above &ndash; you could do the same string comparison tests on the <code>[[Class]]</code> property, for instance &ndash; but I missed these out. There&rsquo;s probably a huge section missed out here (I'd forgotten <code>instanceof</code> existed until after the first draft of this post, for instance). If you can think of any more, let me know here or on <a href="https://twitter.com/intent/tweet?text=@thingsinjars%20Yo,">The Twitter</a>.</p>
<p>I'll also reiterate my point from earlier: most of these are deliberately useless or inefficient. The point here isn't to find better ways to do things, it's to practice doing what you do every day. The more you <em>play</em> while being a web developer, the less you need to <em>work</em>.</p>      </div>
]]></description>
<pubDate>Mon, 09 Jan 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Dun-dun-Duuuuun</title>
<link>http://thingsinjars.com/post/444/dun-dun-duuuuun/</link>
<guid>http://thingsinjars.com/post/444/dun-dun-duuuuun/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-444">
        <p><a href="http://thingsinjars.com/post/444/dun-dun-duuuuun/">Dun-dun-Duuuuun</a></p>
<h2>Or, to put it another way: Done.</h2>

<p>After chatting with my <a href="http://jennifuchs.tumblr.com/">co-conspirator</a> in <a href="http://museum140.com">Museum140</a>, I was finally convinced to do a list of stuff I started and finished in 2011. I'm usually a bit reluctant to write these kinds of things down because it borders on trumpet-blowing but at least this way, I'll have something to prompt me when I start going senile and remaking old ideas.</p>

<h2>Personal</h2>
<p>Before getting to the lists, I have to mention that this time last year I was living in Edinburgh, working at <a href="http://www.nms.ac.uk/">National Museums Scotland</a> and being sleep-deprived by my newborn son. This year, I'm living in Berlin, working at Nokia Maps and being sleep-deprived by my teething one-year-old son.</p>

<p>My job at Nokia is seriously kick-ass. Aside from spending most days figuring out how to do cool stuff in clever ways, I've been getting actively involved in organising our weekly Tech Talks.</p> 

<h2>Websites</h2>
<p>These are sites I built or helped build with Jenni or with the rest of my awesome team at Nokia.</p>
<ul>
<li><a href="http://ceca.icom.museum/">ceca.icom.museum</a></li>
<li><a href="http://shelvi.st/">shelvi.st</a> (<a href="http://thingsinjars.com/post/367/shelvist/">blog post</a>)</li>
<li><a href="http://museum140.com/">museum140.com</a></li>
<li><a href="http://maps.nokia.com/city/germany/berlin">Nokia Maps City Pages</a></li>
</ul>

<h2>Tools</h2>
<p>Things I built to make my life easier which I hope others might find useful.</p>
<ul>
<li><a href="https://github.com/thingsinjars/jQuery-Scoped-CSS-plugin">Scoped CSS polyfill</a> (<a href="http://thingsinjars.com/post/360/scoped-style/">blog post</a>)</li>
<li><a href="https://github.com/thingsinjars/TweetArchiver">TweetArchiver</a></li>
<li><a href="http://www.8bitalpha.com/">8-bit Alpha</a> (<a href="http://thingsinjars.com/post/368/8-bit-alpha/">blog post</a>)</li>
</ul>

<h2>Book</h2>
<p>Although I first published the book last year, this year, I did try out the &lsquo;<a href="http://thingsinjars.com/post/428/explanating/">Read now, Pay Later</a>&rsquo; experiment this year. I'll let you know how that's going later.</p>
<ul><li><a href="http://explanating.com">Explanating</a></li></ul>

<h2>Video</h2>
Having missed out on presenting it at a conference, I gathered together a bunch of stuff I learnt while working at NMS.
<ul><li><a href="http://thingsinjars.com/post/382/html5-for-large-public-bodies/">HTML 5 for Large Public Bodies</a></li></ul>


<h2>Digital Toys</h2>
<p>These are the most fun bits. The silly, experimental games, gadgets and fun ways to waste time.</p>
<ul>
<li><a href="http://thelab.thingsinjars.com/insta-art.html">Insta-Art</a></li>
<li><a href="http://apps.angryrobotzombie.com/knot">Knot</a> (<a href="http://thingsinjars.com/post/390/knots/">blog post</a>)</li>
<li><a href="http://apps.angryrobotzombie.com/torch">Torch</a> (<a href="http://thingsinjars.com/post/401/torch/">blog post</a>)</li>
<li><a href="http://thelab.thingsinjars.com/sine/">Sine</a> (<a href="http://thingsinjars.com/post/429/sine/">blog post</a>)</li>
<li><a href="http://thelab.thingsinjars.com/CSSKart/">3D CSS Mario Kart</a> (<a href="http://thingsinjars.com/post/434/super-mario-kart-css/">blog post</a>)</li>
</ul>

<h2>Still to do...</h2>
<p><strong>Get the Nokia Web Dev blog off the ground. </strong>Don't currently have the slightest idea how to go about it but we've got some world-class webdevs here and we should share some of those smarts.</p> 

<p><strong>Write articles for other people.</strong> I write a lot and, often, my only editor is myself. I have no idea if any of this is any good to anyone. The best way to find out is to try writing for another editor some time.</p> 

<p><strong>Present a lot more.</strong> As someone who, at one point, used to make his living standing in front of a theatre full of people being funny at them, I kinda miss that in my day-to-day.</p> 

<p><strong>Not move country.</strong> Seems like a simple plan but I've failed at it 3 out of the last 5 years. </p>      </div>
]]></description>
<pubDate>Mon, 02 Jan 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Latest 140byt.es offerings</title>
<link>http://thingsinjars.com/post/442/latest-140bytes-offerings/</link>
<guid>http://thingsinjars.com/post/442/latest-140bytes-offerings/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-442">
        <p><a href="http://thingsinjars.com/post/442/latest-140bytes-offerings/">Latest 140byt.es offerings</a></p>
<p>Long-term readers (a.k.a. my Mum) might remember my <a href="http://js1k.com/">JS1K</a> <a href="http://thingsinjars.com/post/296/maze-1k/">efforts</a> <a href="http://thingsinjars.com/post/292/elementally-my-dear-javascript/">last</a> <a href="http://thingsinjars.com/post/294/art-maker-1k/">year</a> and the subsequent discussion of <a href="http://thingsinjars.com/post/293/the-quest-for-extreme-javascript-minification/">Extreme JS Minification</a>. The same kind of mindset that inspired <a href="https://twitter.com/#!/kuvos">qfox</a> to create that competition also inspired <a href="https://twitter.com/#!/jedschmidt">Jed</a> to create <a href="http://140byt.es/">140 Bytes</a>. As with JS1K, the clue is in the name, you have the length of a tweet &ndash; 140 characters &ndash; to create something cool or clever in JS.</p>

<p>I won't go into any more detail here, if you're interested, you've either already heard about it or would do better clicking around the <a href="http://140byt.es/">140bytes site</a> or reading the comments on the <a href="https://gist.github.com/962807">master gist</a>.</p>

<h2>My entries</h2>
<p>Following last week's draggable file script, I started messing about with making it small enough to qualify and, predictably, got hooked. Here are four I made last weekend.</p>

<p>The scripts below are directly embedded from <a href="https://github.com/">GitHub</a> and are the minified, highly compressed versions. I recommend clicking through to the original gist for each of them where you'l find a file called <code>annotated.js</code> which talks through the code.</p>

<h3><a href="http://gist.github.com/1466219">Create a draggable file on-the-fly</a></h3>
<p>The code from <a href="http://thingsinjars.com/post/440/create-a-draggable-file-on-the-fly-with-js/">last week</a> shrunk down. </p>


<h3><a href="http://gist.github.com/1460798">Detect Doctype</a></h3>
<p>There's no simple way to access the current document's doctype as a string. There is already a <code>document.doctype</code> object so you might expect (or, at least I'd expect) you could do a <code>.toString()</code> or <code>.asDoctypeString</code> or something like that. Nope. Nothing. You have to manually recreate it as a concatenation of properties. A quick discussion with <a href="http://twitter.com/kirbysayshi">kirbysayshi</a> and <a href="http://twitter.com/mmarcon">mmarcon</a> came up with a few alternative methods (Max's is quite devious, actually) before eventually culminating in this.</p>


<h3>Chainify and Propertize</h3>
<p>This began as a very minimal implementation of <a href="https://twitter.com/#!/leaverou">Lea Verou's</a> <a href="http://lea.verou.me/chainvas/">Chainvas</a>. The idea is to enhance various constructors (Element, Node, etc.) so that each method returns the original object. This means that you can then chain (jQuery-style) any built-in function. Each constructor is also enhanced with a .prop function which allows property setting in a similarly chainable manner. For a better description, read through <a href="http://lea.verou.me/chainvas/">the Chainvas site</a>. </p>


      </div>
]]></description>
<pubDate>Sat, 17 Dec 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Homemade Lanyard</title>
<link>http://thingsinjars.com/post/441/homemade-lanyard/</link>
<guid>http://thingsinjars.com/post/441/homemade-lanyard/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-441">
        <p><a href="http://thingsinjars.com/post/441/homemade-lanyard/">Homemade Lanyard</a></p>
<p>I'm currently looking for new earphones as my Klipsch ones finally gave out on me last week. Until I get some (Christmas is coming, after all), I decided to rummage around in my 'retired headphones' box (everyone's got one, no?) and found this:</p>

<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/expanded/full-lanyard.jpg" rel="lightbox[441]" title="Full Homemade Lanyard"><img src="http://thingsinjars.com/uploaded/images/thumbs/full-lanyard.jpg" alt="Full Homemade Lanyard" /></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/expanded/lanyard-detail.jpg" rel="lightbox[441]" title="Homemade Lanyard"><img src="http://thingsinjars.com/uploaded/images/thumbs/lanyard-detail.jpg" alt="Homemade Lanyard" /></a></li>
</ul>

<p>Back when I was using my second generation iPod nano, I needed something that combined the usefulness of the lanyard attachment but with good quality headphones. As I couldn't find anything, I got a pair of Sennheiser CX300s, an old USB connector cable and a metre of red ribbon and made my own.  Once the USB end was cut off, I looped it round and glued it ends together then wrapped the join in <a href="http://en.wikipedia.org/wiki/Thread_seal_tape">plumbers' PTFE tape</a> to seal it. The headphones were wired round, fastened with cable ties and then sewn together with the ribbon to make the neck bit comfortable. The iPod connector has two little clips in it which was plenty to hold the lightweight iPod Nano in place under my t-shirt and on that model, the headphone jack was on the bottom so the whole thing clipped together nicely.</p>

<p>The sound quality was as good as you'd expect from Sennheisers and I actually surprised myself with the build quality when I had to, yesterday, dismantle them after almost 4 years. Unfortunately, the iPhone 4 is a little bit too chunky to wear under a t-shirt. I got some odd looks when I tried.</p>

      </div>
]]></description>
<pubDate>Sat, 17 Dec 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Create a draggable file on-the-fly with JS</title>
<link>http://thingsinjars.com/post/440/create-a-draggable-file-on-the-fly-with-js/</link>
<guid>http://thingsinjars.com/post/440/create-a-draggable-file-on-the-fly-with-js/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-440">
        <p><a href="http://thingsinjars.com/post/440/create-a-draggable-file-on-the-fly-with-js/">Create a draggable file on-the-fly with JS</a></p>
<p>Here's a useful little code snippet if you're building a web application. It's a simple way of making the boundary between web-browser and platform a bit smaller. It allows you to create a file (text, html, whatever) in in your page which the user can drag onto their desktop (if their browser supports the dragstart event and dataTransfer methods).</p>

<pre><code>document.getElementById('downloadElement').addEventListener("dragstart", function (e) {
  e.dataTransfer.setData("DownloadURL", "text/html:filename.html:data:image/png;base64," + btoa(fileContent));
});
</code></pre>

<p>A description of the code:</p>
<ul>
 <li>attach an event listener to the draggable element you specify (<code>downloadElement</code>)</li>
<li>when you start to drag it (<code>dragstart</code>),</li>
<li>it creates a dataTransfer object (with the type <code>DownloadURL</code>)</li>
<li>and sets the content of that to be whatever you pass it (<code>fileContent</code>)</li>
<li>It uses <code><a href="https://developer.mozilla.org/en/DOM/window.btoa">btoa()</a></code> to encode the string data as a base64-encoded string.</li>
<li>When you combine this with the MIME-type (<code>text/html</code>),</li>
<li>you can create a file with the specified name (<code>filename.html</code>) when the user releases the drag in their local file system.</li>
<li>The fake MIME-type (<code>image/png</code>) is there as part of the object data to convince the browser this is a binary file (which it is, even though it's not an image).</li>
</ul>

<p>Note: The element this is attached to (<code>downloadElement</code> above) should either be draggable by default (image, link or text selection) or have the draggable attribute set otherwise this'll do nothing.</p>

<p>Credit goes to <a href="http://paul.kinlan.me/">Paul Kinlan</a> for using this in <a href="http://appmator.appspot.com/">Appmator</a> which is where I first saw this done this way. He actually uses it alongside some extremely clever JS zip-file creation stuff, too, it's definitely worth digging through the source there.</p>

<p>You can find out more about the drag events on the <a href="https://developer.mozilla.org/En/DragDrop/Drag_Operations">MDN</a>.</p>      </div>
]]></description>
<pubDate>Thu, 08 Dec 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Simple and clever beats clever</title>
<link>http://thingsinjars.com/post/439/simple-and-clever-beats-clever/</link>
<guid>http://thingsinjars.com/post/439/simple-and-clever-beats-clever/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-439">
        <p><a href="http://thingsinjars.com/post/439/simple-and-clever-beats-clever/">Simple and clever beats clever</a></p>
<p>When messing about with another little game idea, I found myself retyping (for the umpteenth time) the same little bit of value bounding code I use a lot:</p>

<pre><code>var x = Math.max(0, Math.min(y, 1))</code></pre>

Which basically translates to:

<pre><code>"Set x to be the value of y as long as it's between 0 and 1. 
If not, set it to 
  0 if it's smaller or 
  1 if it's larger."</code></pre>

<p>Of course, 0 and 1 don't need to be the boundaries, I'm just using them for convenience.</p>

<p>Instead of continuing with the game, I decided to take a little tangent and see if there was any way I could rewrite this so that the syntax was a bit more obvious. I'd like to be able to use syntax like:</p>

<pre><code>x = [0 &lt; y &lt; 1]</code></pre>

<p>to mean the same. Written exactly as above, JS will try and evaluate left-to-right, changing the comparisons to booleans. The statement would become</p>

<pre><code>y = 0.5

x = [0 &lt; y &lt; 1]
x = [0 &lt; 0.5 &lt; 1]
x = [true &lt; 1]
x = [false]</code></pre>

<p>Similarly:</p>

<pre><code>y = -0.5

x = [0 &lt; y &lt; 1]
x = [0 &lt; -0.5 &lt; 1]
x = [false &lt; 1]
x = [true]</code></pre>

<p>My first thought was to be clever about it, I wanted to try and figure out how to partially evaluate the expression and take the different outcomes to figure out the logic required. If '0 < y' was false, then y is less than zero therefore outside our bounds, the return value should then be 0. If the first part is true and the second is false then we know the value is higher than our bounds....etc and so on.</p>

<p>This proved to be a logical dead-end as there was no good way to partially evaluate the statements. Not without preparsing the JS, anyway. Which leads me onto the second attempt...</p>

<h2>Preparsing the JS</h2>

<p>The next attack on the problem was the idea of reading the JS as a string, shuffling it around quickly and silently (not like a ninja, more like a speedy librarian in slippers) and put it back where it was.</p>

<p>So I began to look at ways to recreate that. I remembered from many, many years ago (two, actually) <a href="http://alexsexton.com/" title="AlexSexton.com">Alex Sexton</a> creating the genius abomination that is <a href="http://summerofgoto.com/" title="The Summer of Goto | Official Home of Goto.js">goto.js</a> and how that used some kind of preparsing. A quick skim through the code later and I ended up on <a href="http://james.padolsey.com/" title="Home &ndash; James Padolsey">James Padolsey's site</a> looking at <a href="https://github.com/padolsey/parseScripts">parseScripts.js</a>.</p>

<p>In the end, all I needed to do was include parseScripts (which is a generalised form of the code I ended up using for the <a href="http://thingsinjars.com/post/424/whitehat-syndication/" title="">whitehat SEO question</a> from last month) and provide a new parser function and script type.</p>

<pre><code>parseScripts(/:bound/, function(unparsed) {
 return unparsed.replace(/\[(\d)\s*&lt;\s*(\w)\s*&lt;\s*(\d)\]/g, "Math.max($1, Math.min($2, $3))");
})</code></pre>

<p>I'm not saying parseScript isn't clever because it most definitely is but I am saying it's simple. There's not always a need to branch off into deep technical investigations of partial evaluation when a simple search-and-replace does the job better and faster.</p>

<p>For someone always going on about bringing simplicity and pragmatism into development, you'd think I'd have gotten there faster...</p>

<h2>Bounded Range</h2>
<p>The final <a href="http://thelab.thingsinjars.com/bounded/">bounded range syntax code is available here</a> (hint: view the console). It's silly but it was a fun half-hour.</p>

<h2>Improvements?</h2>
<p>Do you know of any better way to do this? Is there a clever parsing trick we can use instead? Is there, indeed, any language which has this syntax?</p>
      </div>
]]></description>
<pubDate>Sat, 03 Dec 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>CSS Verification Testing</title>
<link>http://thingsinjars.com/post/437/css-verification-testing/</link>
<guid>http://thingsinjars.com/post/437/css-verification-testing/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-437">
        <p><a href="http://thingsinjars.com/post/437/css-verification-testing/">CSS Verification Testing</a></p>
<p>It&#x27;s difficult to test CSS. In <a href="http://maps.nokia.com/">Nokia Maps</a>, we use lots of different kinds of automated tests to ensure the build is doing what it&#x27;s supposed to do &ndash; <a href="http://pivotal.github.com/jasmine/">Jasmine</a> for JS unit tests, <a href="http://jbehave.org/">jBehave</a> for Java acceptance tests, a whole load of integration tests and systems to make sure all along the process that we know as soon a something goes wrong.</p>

<p>CSS has typically been left out of this process &ndash; not just in our team but generally throughout the industry &ndash; because it&#x27;s a difficult thing to test. CSS is a declarative language meaning that the CSS of a page doesn&#x27;t describe how the page is to accomplish the task of turning text red, for example, it simply says &#x27;the text should be red&#x27; and the implementation details are left up to the browser. This doesn&#x27;t fit well into typical testing strategies as there is no sensible way to pass information in to check the outputs are as expected. With a declarative language, there is very little logic around which you can wrap a test. In essence, the bit you would normally test is the bit handled by the browser. About the closest CSS gets to having continuous-deployment style tests is to run your files against the in-house style guide using <a href="http://csslint.net/">CSSLint</a>.</p>

<p>That&#x27;s not to say people haven&#x27;t tried testing CSS. There are lots of opinions on how or why it should be done but with no concrete answers. There has also been a lot of thinking and quite a lot of work done in the past to try and solve this requirement. <a href="http://morethanseven.net/2008/10/13/unit-testing-css-looking-solution.html">This article from 2008</a> and <a href="http://blog.jonnay.net/archives/695-Unit-testing-CSS-and-HTML.html">this article from 2006</a> both propose a potential route to investigate for testing strategies.</p>

<p>In summary, the two main approaches used are:</p>
<ul>
<li>Generate images from the rendered HTML and compare differences (c.f. <a href="https://github.com/garethr/css-test">css-test by Gareth Rushgrove</a>)</li>
<li>Specify expected values and compare actual values (<a href="https://github.com/gagarine/CSSunit">cssUnit</a>, <a href="http://www.trisis.co.uk/blog/?p=356">CSSUnit</a>)</li>
</ul>

<p>There must be something about the desire to test CSS and the name Simon as both <a href="https://github.com/gagarine/CSSunit">Simon Perdrisat</a> and <a href="http://www.trisis.co.uk/blog/?p=356">Simon Kenyon Shepard</a> created (separate) unit-testing frameworks called &#x27;CSSUnit&#x27;. And there&#x27;s me, obviously.</p>

<p>As a related aside, there may also be something to do with working at Nokia and wanting to test CSS as Simon Shepard is the Tech Lead on Nokia Maps although I stumbled across his project completely randomly outside work. Weird.</p>


<p>Another important related note: there&#x27;s no point in developing a CSS testing framework for <a href="http://en.wikipedia.org/wiki/Test-driven_development">Test-Driven Development</a>. Again, this is an aspect of being a declarative language but, by the time you&#x27;ve written your test, you&#x27;ve written your code. There&#x27;s no Red-Green pattern here. It either does what you intended it to or it doesn&#x27;t.</p>

<p>In essence, the only way to test CSS is by verification testing &ndash; the kind of thing you do before and after refactoring your styles. This, essentially, involves working within your normal process until the job is done then creating &#x27;snapshots&#x27; of the DOM and capturing the current cascaded styles. You can then refactor, rework and reorganise your CSS as much as you like and, as long as the combination of snapshot DOM plus CSS produces the same results as before, you can be confident that your entire system still appears the same way.</p>

<h2>Get to the point...</h2>
<p>Why the long ramble about CSS testing strategies? Well, unsurprisingly, I&#x27;ve had a go at it myself. My approach falls into the second category mentioned above &ndash; measure styles once finished and create secure test-beds of DOM structure which can have CSS applied to them. The test system is currently being run through its paces in <a href="http://maps.nokia.com/city/germany/berlin">Nokia Maps City Pages</a> (my bit of maps) and, if it passes muster, I&#x27;ll put it out into the big, wide world.</p>
      </div>
]]></description>
<pubDate>Wed, 28 Dec 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Whiteboard Laptop Lid</title>
<link>http://thingsinjars.com/post/435/whiteboard-laptop-lid/</link>
<guid>http://thingsinjars.com/post/435/whiteboard-laptop-lid/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-435">
        <p><a href="http://thingsinjars.com/post/435/whiteboard-laptop-lid/">Whiteboard Laptop Lid</a></p>
<p>I use whiteboards a lot. Whether I'm coding, explaining some concept or other, sharing the results of a meeting, wherever. If there's a whiteboard nearby, I'm quite likely to jump up and start drawing big diagrams with lots of arrows and wavy lines. When there's not a whiteboard, I still jump up but I tend to lean more towards big handy gestures drawing diagrams in the air (I recently watched a video of myself presenting with the sound turned down and I looked like an overenthusiastic mime artist dancing to 'Vogue').</p>

<p>To make sure I always have a whiteboard to hand, I roped in <a href="http://www.museum140.com/">Jenni</a> to help with a little home craft-making.</p>

<h2>D.I.Y. Laptop-lid Whiteboard</h2>

<h3>Blue Peter style list of things:</h3>
<p>You'll need scissors and/or a craft-knife, double-sided sticky tape, a measuring tape, a bit of sturdy white cardboard or a thing sheet of opaque PVC and some sticky-backed clear plastic. You'll also need a laptop and an grown-up to help you with the cutting.</p>

<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/expanded/1.materials.jpg" rel="lightbox[435]" title="Scissors and plastic"><img src="http://thingsinjars.com/uploaded/images/1.materials.jpg" alt="Scissors and plastic" /></a></li></ul>

<p>First, measure the top of your laptop and figure out how big your whiteboard can be and draw that on your cardboard or plastic (from now on referred to as 'white board').</p>

<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/expanded/2.measuring.jpg" rel="lightbox[435]" title="Measure twice..."><img src="http://thingsinjars.com/uploaded/images/2.measuring.jpg" alt="Measure twice..." /></a></li></ul>

<p>Next, cut your cardboard or plastic to the right size. Remember to measure twice and cut three times or something like that. I can't remember exactly but there some ratio of measuring to cutting. Do that.</p>

<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/expanded/3.cut.jpg" rel="lightbox[435]" title="...cut three times"><img src="http://thingsinjars.com/uploaded/images/3.cut.jpg" alt="...cut three times" /></a></li></ul>

<p>If you're using a piece of shiny PVC or something like that, you can miss this next bit. If you're using cardboard or something else, you'll need to cover it with the transparent sticky-backed plastic.</p>

<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/expanded/4.covering.jpg" rel="lightbox[435]" title="Sticky-backed plastic"><img src="http://thingsinjars.com/uploaded/images/4.covering.jpg" alt="Sticky-backed plastic" /></a></li></ul>

<p>The final preparation stage is to put the double-sided sticky tape on the back and position it on your laptop lid. </p>

<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/expanded/5.sticking.jpg" rel="lightbox[435]" title="Double-sided sticky tape"><img src="http://thingsinjars.com/uploaded/images/5.sticking.jpg" alt="Double-sided sticky tape" /></a></li></ul>

<p>Try not to take any photos one-handed while doing this step or this may happen:</p>

<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/expanded/6.sticky-stuck.jpg" rel="lightbox[435]" title="Oops."><img src="http://thingsinjars.com/uploaded/images/6.sticky-stuck.jpg" alt="Oops." /></a></li></ul>

<p>There you go. A portable, take-anywhere whiteboard in 10 minutes. Apart from needing a pen, of course, and a cloth to wipe it so you don't end up with smudges all over your laptop bag, we're done.</p>

<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/expanded/7.on-top.jpg" rel="lightbox[435]" title="Stuck."><img src="http://thingsinjars.com/uploaded/images/7.on-top.jpg" alt="Stuck." /></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/expanded/8.see-through.jpg" rel="lightbox[435]" title="Not completely opaque."><img src="http://thingsinjars.com/uploaded/images/8.see-through.jpg" alt="Not completely opaque." /></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/expanded/omg.jpg" rel="lightbox[435]" title="Action shot!"><img src="http://thingsinjars.com/uploaded/images/omg.jpg" alt="Action shot!" /></a></li>
</ul>

<p>I can now take my whiteboard with me everywhere I go for a meeting. Long may the diagramming continue.</p>      </div>
]]></description>
<pubDate>Sat, 26 Nov 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Super Mario Kart CSS</title>
<link>http://thingsinjars.com/post/434/super-mario-kart-css/</link>
<guid>http://thingsinjars.com/post/434/super-mario-kart-css/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-434">
        <p><a href="http://thingsinjars.com/post/434/super-mario-kart-css/">Super Mario Kart CSS</a></p>
<h2>Silly CSS Fun for a Sunday Afternoon</h2>
<p>Yesterday, I decided to mess around with 3D CSS transforms. I've used them here and there for various things (the flip animations in <a href="http://shelvi.st/thingsinjars">Shelvi.st</a>, for example) but nothing silly.</p>

<p>My mind wandered back to an early <a href="http://www.nihilogic.dk/labs/mariokart/">HTML5 canvas demo</a> I saw ages ago where Jacob Seidelin had written Super Mario Kart in JS and I wondered if it would be possible to do the pixel-pushing part of that demo in CSS.</p>

<p>An hour later and we have this:</p>
<p><a href="http://thelab.thingsinjars.com/CSSKart/">Super Mario Kart CSS</a></p>

<p>Yes, it's silly. Yes, it's nothing like playing Mario Kart and, no, there isn't any acceleration. That wasn't the point, however. View the source to see the description of the rotations and transforms.</p>      </div>
]]></description>
<pubDate>Mon, 14 Nov 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Poor man's touch interface</title>
<link>http://thingsinjars.com/post/433/poor-mans-touch-interface/</link>
<guid>http://thingsinjars.com/post/433/poor-mans-touch-interface/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-433">
        <p><a href="http://thingsinjars.com/post/433/poor-mans-touch-interface/">Poor man's touch interface</a></p>
<p>Here's a little code snippet for today.</p>

<p>While I was making the <a href="http://thingsinjars.com/post/434/super-mario-kart-css/">3D CSS Mario Kart</a>, I needed a simple, drop-in bit of code to handle touch interfaces. I looked through some old experiments and found a rough version of the code below. It was based on this <a href="http://stackoverflow.com/questions/3691461/remove-key-press-delay-in-javascript">KeyboardController</a> by Stack Overflow user <a href="http://stackoverflow.com/users/18936/bobince">Bob Ince</a>.</p>

<p>It doesn't do anything clever. All it does is provide a simple way to attach functionality to touch events in different areas of the screen &ndash; top-left, top-center, top-right, middle-left, middle-center, middle-right, bottom-left, bottom-center, bottom-right. My apologies to any Brits for the spelling of centre as 'center'. It's the Internet, we have to.</p>

<h2>How to use</h2>
<p>Include this code:</p>
<pre><code>
function TouchController(areas, repeat) {
  var touchtimer;
  document.onmousedown = document.ontouchstart = document.ontouchmove = function(e) {
    var position;
    e.preventDefault();
    e.touches = [{&#x27;clientX&#x27;:e.pageX,&#x27;clientY&#x27;:e.pageY}];
    switch(true) {
    case (e.touches[0].clientY&lt;window.innerHeight/3) : 
        position = &#x27;top&#x27;;
        break;
    case (e.touches[0].clientY&gt;(2*window.innerHeight)/3) : 
        position = &#x27;bottom&#x27;;
        break;
    default : 
        position = &#x27;middle&#x27;;
        break;
    }
    position+=&#x27;-&#x27;;
    switch(true) {
    case (e.touches[0].clientX&lt;window.innerWidth/3) : 
        position += &#x27;left&#x27;;
        break;
    case (e.touches[0].clientX&gt;(2*window.innerWidth)/3) : 
        position += &#x27;right&#x27;;
        break;
    default : 
        position += &#x27;center&#x27;;
        break;  
    }

    if (!(position in areas)) {
      return true;
    }

    areas[position]();
    if (repeat!==0) {
      clearInterval(touchtimer);
      touchtimer= setInterval(areas[position], repeat);
    }
    return false;
  };
  // Cancel timeout
  document.onmouseup = document.ontouchend= function(e) {
  clearInterval(touchtimer);
  };
};
</code></pre>

<p>Now, all you need to do to attach a function to a touch event in the top-left area of the screen is:</p>
<pre><code>TouchController({
  'top-left': function() { topLeftFunction();}
}, 20);
</code></pre>

<p>I use this for direction control in the Mario Kart experiment which maps exactly onto the cursor keys used for the normal control.</p>
<pre><code>TouchController({
  'top-left': function() {  // UP + LEFT
				drawMap.move({y: 2}); 
				drawMap.move({z: drawMap.z + 2}); 
				drawMap.sprite(-1) 
			  },
  'top-center': function() {  // UP
				drawMap.move({y: 2}); 
			  },
  'top-right': function() {  // UP + RIGHT
				drawMap.move({y: 2}); 
				drawMap.move({z: drawMap.z - 2}); 
				drawMap.sprite(1) 
			  },

  'middle-left': function() {  // LEFT
				drawMap.move({z: drawMap.z + 2}); 
				drawMap.sprite(-1) 
			  },
  'middle-right': function() {  // RIGHT
				drawMap.move({z: drawMap.z - 2});
				drawMap.sprite(1) 
			  },

  'bottom-left': function() {  // DOWN + LEFT
				drawMap.move({y:  - 2}); 
				drawMap.move({z: drawMap.z + 2}); 
				drawMap.sprite(-1)  
			  },
  'bottom-center': function() { 
				drawMap.move({y:  - 2}); 
			  },
  'bottom-right': function() {  // DOWN + RIGHT
				drawMap.move({y:  - 2}); 
				drawMap.move({z: drawMap.z - 2}); 
				drawMap.sprite(1)  
			  },
}, 20);
</code></pre>

<p>If you need anything clever or you need two or more touches, you should use something else. This is just a simple drop-in for when you're copy-paste coding and want to include touch-screen support.</p>
      </div>
]]></description>
<pubDate>Thu, 17 Nov 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Silly CSS Gradient</title>
<link>http://thingsinjars.com/post/432/silly-css-gradient/</link>
<guid>http://thingsinjars.com/post/432/silly-css-gradient/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-432">
        <p><a href="http://thingsinjars.com/post/432/silly-css-gradient/">Silly CSS Gradient</a></p>
<p>Okay, here's a bit of silliness. I did a little presentation yesterday with some slides which I built using <a href="http://hakim.se/">Hakim El Hattab's</a> 3D <a href="http://hakim.se/experiments/css/slideshow/#/">CSS Slideshow</a>. I decided to have some fun with the last slide. </p>

<p><a href="http://thelab.thingsinjars.com/thats-all.html">The Looney Tunes &ldquo;That's all Folks&rdquo;  end title using radial gradients</a>.</p>

<p>I was doing my presentation using Chrome so I'm allowing myself some leeway that it's not fully cross-browser.</p>      </div>
]]></description>
<pubDate>Tue, 08 Nov 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>That Version-y Control-y Stuff</title>
<link>http://thingsinjars.com/post/431/that-version-y-control-y-stuff/</link>
<guid>http://thingsinjars.com/post/431/that-version-y-control-y-stuff/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-431">
        <p><a href="http://thingsinjars.com/post/431/that-version-y-control-y-stuff/">That Version-y Control-y Stuff</a></p>
<p>If you&rsquo;re reading this site, you&rsquo;re probably not a beginner. The following article is probably beneath you. Go on, read it anyway.</p>
<p>Just in case you don&rsquo;t know, a Version Control System (VCS) is pretty much the most important thing ever in the history of anything ever. Just think about it conceptually: the ability to stand back and look at everything you&rsquo;ve ever done, choose the good bits, drop the bad bits, mop up the mistakes… it gives you the freedom to “Play with it ‘til it breaks” with the safety net that you can always go back and fix it again.</p> 
<p>You Get To Play With Time Itself!</p>
<p>There are many, many debates about the different methodologies you can use with version control and which technologies are best suited to which methodologies and which interfaces are best suited to which technologies and so on ad nauseam. The main concepts of working with any VCS are essentially the same, however.</p>
<ol>
<li>It must be almost invisible.</li>
<li>It must be completely reliable</li>
<li>You mustn&rsquo;t rely on it</li>
</ol>
<h2>It must be almost invisible</h2>
<p>If you have never used a VCS before, it must fit perfectly into your workflow otherwise you won&rsquo;t do it. It isn&rsquo;t until you&rsquo;ve been saved from potential disaster by a system that you will truly appreciate it and see the value in working it into your process. If you have or are currently using a VCS, think about when and how you use it. Does it require launching a new application or does it run in the background? Do you have to manually check things in or is it seamless versioning? The more effort required to mark a version, the less often you&rsquo;ll do it as it breaks the flow of development</p>
<p>On the other hand, if the process is completely invisible, you might forget it&rsquo;s there. It&rsquo;s exactly the same as <a href="http://thingsinjars.com/post/408/workflow-the-flow-of-work/">assuming your changes are going live on the server</a> &ndash; the moment you assume it happens, it doesn&rsquo;t. You still need some level of manual checking.</p>
<h2>It must be completely reliable</h2>
<p>This is fairly obvious, hopefully. You need the security that your version system is working otherwise you might again be tempted to miss it out – why take the extra step required to version a file if it&rsquo;s not going to be there when I need it?</p>
<p>If you&rsquo;re hosting your own repositories internally to your organisation, don&rsquo;t put it on a server older than you are. The safest route to go down is contracted external hosting. That way, it&rsquo;s someone&rsquo;s job to make sure your datums are secure.</p>
<h2>You mustn&rsquo;t rely on it</h2>
<p>Always have a backup. Always have a copy. Always have an escape route. Or something. You should have picked up the theme by now. Version Control Systems are great but as soon as it is the only thing standing between you and a complete failure to deliver a project, it will fail. Or not. It&rsquo;s funny like that.</p>      </div>
]]></description>
<pubDate>Tue, 08 Nov 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Copy-paste coding</title>
<link>http://thingsinjars.com/post/430/copy-paste-coding/</link>
<guid>http://thingsinjars.com/post/430/copy-paste-coding/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-430">
        <p><a href="http://thingsinjars.com/post/430/copy-paste-coding/">Copy-paste coding</a></p>
<p>This weekend, I had a spare couple of hours on Saturday night (as often happens when you have a kid) so I decided to pass the time with a bit of copy-paste coding.</p>

<p>I grabbed a bit of <a href="http://banditracer.eu/carexample/">example code for a top-down racing game</a> built using <a href="http://www.box2d.org/">Box2d</a> and <a href="http://gamejs.org/">GameJs</a>. I then grabbed a <a href="http://maps.google.com/">Google Maps</a> demo and a <a href="http://maps.nokia.com/">Nokia Maps demo</a> and smooshed them together. I've seen a few racing games before so I know there's nothing innovative here, it's just a bit of silliness.</p>

<h2>The results</h2>
<ul>
 <li><a href="http://thelab.thingsinjars.com/car2d/index-ovi.html">Driving on Nokia Maps</a></li>
 <li><a href="http://thelab.thingsinjars.com/car2d/index.html">Driving on Google Maps</a></li>
</ul>

<h2>Copy-Paste: Not a bad thing</h2>
<p>There are many developers who will tell you that blindly copy-pasting is a terrible way to code. They make the valid points that you don't understand something if you don't read it properly and that you'll end up stuck down an algorithmic cul-de-sac with no way to three-point-turn your way out (although they may phrase it differently). These are valid points but...</p>

<p>If I'd sat down on Saturday night and thought "I want to build something in Box2D" then gone to the site, downloaded the library, read the docs and loaded the examples, by the time I had understood what I was doing, Sunday morning would have come round and I'd still have GameJS to read up on. There's absolutely no harm in blindly catapulting yourself a long way down the development track then looking round to see where you are. Sure, you'll end up somewhere unfamiliar and you may end up with absolutely no clue what the code around you does but at least you have something to look at while you figure it out. At least a few times, you'll find something almost works and a quick search of the docs later, you've figured it out and know what it's doing.</p>

<p>Basically, copy-pasting together a simple little demo and making it work is a lot more interesting than taking baby-steps through example code and beginner tutorials. Don't be too careful about trying to build something complicated.</p>

<h2>An Idea</h2>
<p>If you're in the mood for copy-paste coding, try taking the two demos above (Google and Nokia), grab the node.js server from the <a href="http://thingsinjars.com/post/412/multi-user-pages/">multi-user page experiment</a> and figure out how to have multiple racers on the same map (by transmitting angle and geo-coords).</p>      </div>
]]></description>
<pubDate>Mon, 31 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Sine</title>
<link>http://thingsinjars.com/post/429/sine/</link>
<guid>http://thingsinjars.com/post/429/sine/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-429">
        <p><a href="http://thingsinjars.com/post/429/sine/">Sine</a></p>
<p>Another game concept prototype &ndash; <a href="http://thelab.thingsinjars.com/sine/">Sine</a></p>

<p>Honestly, I have no idea what I was going for with this one. It started off last weekend with a vague idea about matching patterns of numbers and old-school graphics and I don't know what and ended up with this.</p>

<p>The idea is to make the bottom row match the top row, basically. There are several front-ends to this game so you can choose the style of play you prefer - numbers and letters, waves, colours or a generated sound wave (if you have a shiny new-fangled browser). It uses the nifty little <a href="http://codebase.es/riffwave/">Riffwave library</a> to generate PCM data and push it into an audio element.</p>

<h2>Further development</h2>
<p>If I were to develop this further, I'd try and build it in a modular fashion so that front-ends could be generated really easily and open it to other people to see how many different ways this game could be played. It'd be an interesting social experiment to be able to play what is fundamentally the same game in a dozen different ways. You could find out if visual thinkers processed the information faster than numerical or audio-focused people. Leaderboards could allow different styles of player to compete on the same playing field but with a different ball (hmm, weak sports analogy). The rhythms of the game lend themselves well to generated drum tracks so there's probably something in that area for exploring as well.</p>

<p>At the moment, the code is written as the programming equivalent of stream-of-consciousness &ndash; global variables everywhere, some camel-case, some underscored, vague comments sprinkled around. There's some commented-out code for the wave mode that moves the waves closer together so that there's a time-limit set but I felt it didn't suit the game.</p>


<h2>Warning</h2>
<p>The audio mode is <strong>very</strong> annoying. Seriously. If I were still a full-time game designer, I would not release this due to public health concerns. As I'm now an enthusiastic amateur, here you go :D</p>      </div>
]]></description>
<pubDate>Fri, 21 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Explanating</title>
<link>http://thingsinjars.com/post/428/explanating/</link>
<guid>http://thingsinjars.com/post/428/explanating/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-428">
        <p><a href="http://thingsinjars.com/post/428/explanating/">Explanating</a></p>
<p>I never really marketed it much but I wrote a book called &lsquo;Explanating&rsquo; a couple of years ago. I even decided to self-publish<a href="http://thingsinjars.com/post/428/explanating/#ex-foot-1" id="ex-foot-a">1</a> and organised ISBNs and everything.</p>

<p><a href="http://thingsinjars.com/post/428/explanating/#ex-foot-a" id="ex-foot-1">1</a>My decision to self-publish may or may not have been related to my inability to find an actual publisher, it's impossible to tell.</p>

<p>The book is an "illustrated collection of completely plausible but entirely untrue explanations of everyday phenomena". Basically, it's lots of the kinds of things you might make up to explain something to a kid if you really have no idea. Hence the name &lsquo;Explanating&rsquo; &ndash; it's kinda like explaining but not quite right. It also has a rather nice cheesecake recipe in the appendix. I put it on Lulu and Amazon and didn't really do anything else with it. I did try to get it in the iBookstore but that seems to be a horribly complicated process if you aren't based in the US.</p>

<h2>Now available for the low, low price of...</h2>
<p>Rather than have the book sit around for another few years not doing anything useful, I've decided to try something new. You can now download the book for <strong>free</strong> from <a href="http://explanating.com">explanating.com</a> in your ebook format of choice (PDF, ePub, Mobi). You don't have to pay anything.</p>

<p>Unless you want to.</p>

<p>If you read it and decide you like it, you can come back to the site any time and buy it from Lulu or Amazon for <strong>&pound;1.71</strong> (or the equivalent in USD or EUR or wherever you happen to be). Or not, you could like it and keep it and not pay anything. It's entirely up to you. And your conscience :D.</p>

<h2>Download, read, buy</h2>
<p>I have no idea if anyone will actually take me up on this offer but I hope some people do, at least, enjoy the book. If nothing else, make the cheesecake, it's delicious.</p>

<h2>And that URL once more</h2>
<p><a href="http://explanating.com/">explanating.com</a></p>      </div>
]]></description>
<pubDate>Thu, 13 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>HighlightBlock.vim</title>
<link>http://thingsinjars.com/post/427/highlightblockvim/</link>
<guid>http://thingsinjars.com/post/427/highlightblockvim/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-427">
        <p><a href="http://thingsinjars.com/post/427/highlightblockvim/">HighlightBlock.vim</a></p>
<p>tl;dr: <a href="https://github.com/thingsinjars/HighlightBlock.vim">Here's a Vim plugin to highlight style and script blocks in HTML</a></p>

<p>Okay, this'll be my last vim post for a while. I just couldn't leave it alone, though. </p>

<p>My <a href="http://thingsinjars.com/post/425/cobaltvim/">Cobalt theme</a> was good but it wasn't quite enough. You'll see from the screenshots that the entire HTML page had the same background colour in Vim while the TextMate version changed the background colour inside <code>&lt;style&gt;</code> and <code>&lt;script&gt;</code> blocks. I was surprised how much that bugged me so I figured there must be a way to highlight an entire line. It turns out this isn't a trivial thing to do. Syntax matches will only match to the final character in the line ($), not the width of the screen. No amount of tweaking a colorscheme would allow highlighting all the way across. </p>

<p>After a lot of digging around, I found out about <a href="http://vimdoc.sourceforge.net/htmldoc/sign.html">signs</a>. This is a built-in feature which allows you to add a marker to a line for whatever purpose you want. It can point out debugging information or provide visual checkpoints to mark out things in your document. It's probably very handy but as I've only just started using vim, I don't really know what it's best for. However, as a side-effect, it can also apply a style to the entire screen-width of a line. </p>

<p>Some googling, hacking and probable violation of Vim plugin best-practice, I knocked together this plugin:</p>

<p><a href="https://github.com/thingsinjars/HighlightBlock.vim">HighlightBlocks.vim</a></p>

<p>When this is installed, it will highlight any embedded CSS or JS blocks in a HTML, PHP, Velocity templates or Ruby files. Well, it will apply the syntax class 'HighlightedBlock' to the line. If your theme has a style for that, it will highlight it. Incidentally, I updated the <a href="https://github.com/thingsinjars/Cobalt.vim">Cobalt port</a> to include that style. </p>

<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/expanded/vim-html-highlight-screenshot.png" rel="lightbox[427]"><img src="http://thingsinjars.com/uploaded/images/thumbs/vim-html-highlight-screenshot.png" alt="Screenshot of MacVim with the HighlightBlock plugin"></a></li>
</ul>

<p>It runs on initial load then refreshes every time you exit insert mode.</p>

<p>I might update it later to highlight PHP blocks in HTML or some other things like that but for my current purposes, it's finished. </p>

<h2>Warning</h2>
<ul><li>It pays no attention to existing signs. If you use them, you probably shouldn't use this. If you know of a simple way to group signs together to stop me messing with them, let me know.</li>
<li>When signs are added to a file, an extra two-character column appears to the left of the line numbers. This plugin shrinks the line-numbers column by two characters if signs exist and increases it again when they are removed. This stops everything from jumping around but if you're working on a 10,000 line file, you might see some confusion down the bottom.</li>
</ul>

<h2>Installation</h2>
<p>As with the Cobalt theme, if you're using Janus, add this to <code>~/.janus.rake</code>, I still have no idea if this works. It might. :</p>
<pre><code>vim_plugin_task "HighlightBlock.vim", "git://github.com/thingsinjars/HighlightBlock.vim.git"</code></pre>      </div>
]]></description>
<pubDate>Fri, 07 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Text Editors</title>
<link>http://thingsinjars.com/post/426/text-editors/</link>
<guid>http://thingsinjars.com/post/426/text-editors/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-426">
        <p><a href="http://thingsinjars.com/post/426/text-editors/">Text Editors</a></p>
<p>Many years ago during the text-editor holy wars, I sided neither with the Vi Ninjas nor the Emacs Samurai but instead went a third way &ndash; <a href="http://en.wikipedia.org/wiki/Pico_(text_editor)">Pico</a> (short for Pine Composer). It was the text editing part of the e-mail program I used (<a href="http://www.washington.edu/pine/">Pine</a>). For many years, this served me well. Even today, Pico's successor - <a href="http://www.nano-editor.org/">Nano</a> &ndash; is installed pretty much everywhere. It isn't , however, quite powerful enough for fast-paced web development. Serious, full-time development needs shortcuts and macros, syntax highlighting and snippets. When you spend 10 or more hours every day <a href="http://xkcd.com/722/">pressing buttons to change flashing lights</a>, you need to optimise the way the lights flash.</p>

<p>After Pico, I found <a href="http://www.crimsoneditor.com/">Crimson Editor</a> which served me well for almost 10 years. I eventually started working on a Mac and became a <a href="http://macromates.com/">TextMate</a> user for most of the last 5 years.</p>

<p>In my new job, I find myself jumping from computer to computer to desktop to server quite a lot. The only constant editor available is Vi. Or Vim (Vi Improved). I've been trying to pick it up as a way to ensure I can always jump into a friendly text editor no matter where I am. Besides, these days Vim is the old-new-cool thing that all the cool-old-kids use, particularly MacVim so I thought it was worth giving it a go to see what the fuss was about.</p>

<p>Incidentally, the first thing that always jumped into my head whenever anybody mentioned Vi was the <a href="http://vimgolf.com/">Vim Golf</a> challenge two of my lecturers played while I was at Uni. It's a well-known and surprisingly popular game where two Seventh-dan Vi proficients try to accomplish an edit on a file using the fewest keystrokes. Each morning, one lecturer would lay down a challenge and the other had 24 hours to come up with a solution before presenting it and the next challenge the following day. The (possibly apocryphal) conclusion to the long-running game came when it was discovered that the lecturer who won most often was actually recompiling the network install of Vim every night to include his own custom keyboard shortcuts.</p>

<p>One of the biggest deciding factors in trying it out was actually fellow Edinburgh Web Dev/International Traveller Drew Neil (<a href="https://twitter.com/nelstrom">@nelstrom</a>), creator and voice of the <a href="http://vimcasts.org/">vimcasts.org</a> series of screencasts who is actually writing a book on Vim this very second as I write this. Most people are evangelical about their choice of text editor to the point of rabid fundamentalist, frothing-at-the-mouth, intoning-keyboard-shortcuts craziness (hence my allusions to text-editor holy wars). When I mentioned to Drew that I used Pico instead, his response was long the lines of "Fair enough". This lack of confrontation actually inspired me to try it out. Well played, sir.</p>

<p>In an unrelated aside, I once did an <a href="http://all-sorts.org/blog/illustrations#surrealists">illustration</a> for the '<a href="http://all-sorts.org/blog/illustrations">Collective Nouns Illustrated</a>' project Drew ran.</p>

<p>Anyway, I'll give it a go and see what happens. If you're interested, I recommend reading Yehuda Katz' post '<a href="http://yehudakatz.com/2010/07/29/everyone-who-tried-to-convince-me-to-use-vim-was-wrong/">Everyone Who Tried to Convince Me to use Vim was Wrong</a>'. Don't worry, I'm definitely not going to try and convince anyone to use one code editor over another. You should probably stop using FrontPage, though.</p>      </div>
]]></description>
<pubDate>Thu, 06 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Cobalt.vim</title>
<link>http://thingsinjars.com/post/425/cobaltvim/</link>
<guid>http://thingsinjars.com/post/425/cobaltvim/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-425">
        <p><a href="http://thingsinjars.com/post/425/cobaltvim/">Cobalt.vim</a></p>
<p>What?!</p>

<p>Another port of the TextMate theme 'Cobalt' to Vim?</p>

<p>But there are <a href="https://github.com/jarodl/cobalt.vim">already</a> <a href="https://github.com/sfsekaran/cobalt.vim">so</a> <a href="https://github.com/dterei/VimCobaltColourScheme">many</a>!</p>

<p>Yes. Yes there are. However, the other ones I found were all missing something.  Some had the right colours but in the wrong places, some had most of the right things highlighted but in slightly wrong colours. None of them had coloured the line-numbers. I think this is the most complete port. The initial work was done automatically using <a href="http://coloration.sickill.net/">Coloration</a> and then manually tweaked and added to. I know I should probably have just picked one of the existing GitHub projects, cloned it and pushed to it but I feel it would be a tad presumptuous of me to just turn up in someone's repository one day saying "yeah, you did alright but mine's better". Besides, I've never tried making a theme for Vim before. I've probably done something wrong (see below). If it continues to work for a while without causing any major issues, I might look at pushing it to another repo.</p>

<p>This was done on top of a vanilla install of the excellent <a href="https://github.com/carlhuda/janus">Janus</a> configuration of MacVim so whatever plugins are installed by default may have an affect on this.</p>

<p>There are a few limitations in the syntax files enabled by default so this includes a couple of matches, regions and things that really shouldn't be in a colorscheme file but I've included them because I felt like it and it was the only way to really match some of the highlighting TextMate allows (this is the thing I was referring to above).</p>

<p>I haven't really touched the NerdTree colouring much as it's probably impossible to have different background colours in different panes. Can't guarantee that, though.</p>

<h2>Installation</h2>
<p>There are probably some conventions to do with how to organise a GitHub project so that it can be automatically installed but I've just gone with sticking it in a directory called 'colors' so it can be pulled in from the root of your <code>~/.vim</code> directory.</p>

<p>If you're using Janus, add this to <code>~/.janus.rake</code>, I think it'll work:</p>
<pre><code>vim_plugin_task "Cobalt.vim", "git://github.com/thingsinjars/Cobalt.vim.git"</code></pre>

<p>If you're not using Janus, you probably know what you're doing anyway.</p>

<p>The GitHub project is here:</p>
<ul>
<li><a href="https://github.com/thingsinjars/Cobalt.vim">github.com/thingsinjars/Cobalt.vim</a></li>
</ul>

<h2>Screenshots</h2>
<p>The first of each pair is Vim, the second is the TextMate original.</p>
<h3>Editing CSS</h3>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/expanded/vim-screenshot.png" rel="lightbox[425screen]" title="Vim"><img src="http://thingsinjars.com/uploaded/images/thumbs/vim-screenshot.png"></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/expanded/textmate-screenshot.png" rel="lightbox[425screen]" title="TextMate"><img src="http://thingsinjars.com/uploaded/images/thumbs/textmate-screenshot.png"></a></li>
</ul>
<h3>Editing HTML</h3>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/expanded/vim-html-screenshot.png" rel="lightbox[425htmlscreen]" title="Editing HTML in Vim"><img src="http://thingsinjars.com/uploaded/images/thumbs/vim-html-screenshot.png"></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/expanded/textmate-html-screenshot.png" rel="lightbox[425htmlscreen]" title="Editing HTML in TextMate"><img src="http://thingsinjars.com/uploaded/images/thumbs/textmate-html-screenshot.png"></a></li>
</ul>      </div>
]]></description>
<pubDate>Fri, 07 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Whitehat Syndication</title>
<link>http://thingsinjars.com/post/424/whitehat-syndication/</link>
<guid>http://thingsinjars.com/post/424/whitehat-syndication/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-424">
        <p><a href="http://thingsinjars.com/post/424/whitehat-syndication/">Whitehat Syndication</a></p>
<p>When I refer to Google or Googlebot here, I could really be talking about any web search or web crawler. When I refer to Yahoo, I actually mean Yahoo. Don't get confused.</p>

<p>I recently ran into an interesting SEO problem on a project which has led to a question I just don't know the answer to:</p>

<p>How do you display syndicated content without triggering Google's duplicate content flag?</p>

<p>Hmm... intriguing.</p>

<h2>Background</h2>
<p>To explain the problem more fully (without giving out any project specifics), imagine you have a website. You probably already do so that shouldn't be hard. Now, imagine you fill that website full of original content. Again, that shouldn't be hard. For the sake of example, let's assume you run a news blog where you comment on the important stories of the day.</p>

<p>Next, you figure that your readers also want to read important related facts about the news story. Associated Press (AP) syndicates its content and through the API, you can pull in independently-checked related facts about whatever your original content deals with. So far, so good.</p>

<p>Unfortunately, a thousand other news blogs also pull in the same AP content alongside their original (and some not-so-original) content. Now, when the Googlebot crawls your site, it finds the same content there as it does in a thousand other places. Suddenly, you're marked with a 'duplicate content' black flag and all the lovely google juice you got from writing original articles has been taken away. Boo.</p>

<p>Your first thought might be to reach for the <code>rel="canonical"</code> attribute but that really only applies to entire pages. We need something that only affects a portion of the page.</p>

<h2>Solution</h2>
<p>What you need to do is find a way to include the content in your page when a visitor views it (providing extra value for readers) but prevent Google from reading it (hurting your search ranking). Fortunately, there are some methods for doing this. One involves having the content in an external JS file which is listed in your robots.txt to prevent Google from reading it. Another similar method involves having the content in an external HTML and including it as an iframe, again, preventing crawling via robots.txt. When the reader visits the page, the content is there, when Google visits, it isn't.</p>

<h2>The Problem with the Solution</h2>
<p>Both of the techniques mentioned here involve an extra HTTP request. You are including an external file so the visitor's browser has to go to your server, grab the file and include it. This isn't a huge problem for most sites but when you're dealing with high-traffic, highly-optimised websites, every file transferred counts. You go to all the trouble of turning all background <a href="http://spriteme.org/">images into sprites</a>, why waste extra unnecessary connections on content?</p>
	
<p>There is an extra problem with the JS solution in that the content isn't available to visitors that don't have JS enabled but as I've <a href="http://thingsinjars.com/post/382/html5-for-large-public-bodies/" title="HTML5 for Large Public Bodies">mentioned before</a>, that's only a problem if any of your visitors actually have JS disabled. Only you know that for sure.</p>

<h2>Yahoo's Solution</h2>
<p>Yahoo have a nice solution to this problem. If you include the attribute <code>class="robots-nocontent"</code> on any element, the Yahoo spider (called 'slurp') will ignore the content. Perfect. This does, however, only work for Yahoo. Not perfect.</p>

<h2>My solution</h2>

<p>My attempt at solving this problem which is a combination of SEO and high front-end performance was inspired by the technique <a href="http://googlecode.blogspot.com/2009/09/gmail-for-mobile-html5-series-reducing.html" title="Gmail for Mobile HTML5 Series: Reducing Startup Latency - The official Google Code blog">GMail uses to deliver JS to mobile devices</a>. In their article, Google delivers JS that they don't want run immediately in the initial payload. They figure that the cost of serving a single slightly larger HTTP request is less than the delay in retrieving data on demand.</p>

<p>I use HTML embedded in a JS comment in the original page which is then processed on DOMReady to strip out the comments and inject it into wherever it is supposed to be (identified by the <code>data-destination</code> attribute). I'm doing this on a page which already loads jQuery so this can all be accomplished with a simple bit of code.</p>

<pre><code>&lt;script type=&quot;text/html&quot; class=&quot;norobot&quot; data-destination=&quot;.content-destination&quot;&gt;
 /*!
  &lt;p&gt;This content is hidden on load but displayed afterwards using javascript.&lt;/p&gt;
 */
&lt;/script&gt;
&lt;div class=&quot;content-destination&quot;&gt;&lt;/div&gt;
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
 $(&#x27;.norobot').each(function() {
  _this = $(this);
  $(_this.data(&#x27;destination&#x27;)).html(_this.html().replace(&#x27;/*!&#x27;,&#x27;&#x27;).replace(&#x27;*/&#x27;,&#x27;&#x27;));
 });
&lt;/script&gt;</code></pre>

<h2>Notes on the code</h2>
<p>You may have noticed the <code>type="text/html"</code> attribute on the script block. That's to get around the fact that jQuery parses and executes any script blocks it finds when moving elements around (in an appendTo() or an html(), for example. Adding this attribute tells jQuery to process this as template code. </p>

<p>Also, the opening JS comment here begins <code>/*!</code>. The exclamation mark in this is a directive to any minifiers you might use on the code to tell them not to remove this comment block.</p>

<p>This is also available in a <a href="http://thelab.thingsinjars.com/Post-Load/index.html">standalone page</a>.</p>

<p>This is all a very long setup for my initial question. Does Google read this and, if so, does this affect duplicate content rankings?</p>

<h2>Plus and Minus</h2>
<ul><li><strong>Minus</strong>: The duplicate content is definitely in the page.</li>
<li><strong>Plus</strong>: It's hidden in JavaScript</li>
<li><strong>Minus</strong>: we're using JavaScript to serve different content to users and to google.</li>
<li><strong>Plus</strong>: we're showing less to google than users. Spam techniques show more to increase keyword matches. </li>
<li><strong>Plus</strong>: faster response due to a single http request (Google likes fast pages)</li>
</ul>

<p>Obviously, we could add an extra step of obfuscating the 'hidden' content by reversing it or encoding it. This would definitely hide it from google and it would be trivial to undo the process before showing it to the user but is this step necessary? Part of my reasoning for concluding that Google ignores JS comments is that thousands of sites include the same standard licences bundled with their JS library of choice and don't get penalised. This may, of course, be specific to licences, though.</p>

<p>I can find no definitive answer anywhere on this subject. If you have any good references, please let me know. Alternatively, if you happen to know <a href="http://www.mattcutts.com">Matt Cutts</a>, ask him for me. If I get any conclusive answer, I'll update here.</p>

      </div>
]]></description>
<pubDate>Mon, 03 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>jQuery Detach Scrollbars Plugin </title>
<link>http://thingsinjars.com/post/422/jquery-detach-scrollbars-plugin-/</link>
<guid>http://thingsinjars.com/post/422/jquery-detach-scrollbars-plugin-/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-422">
        <p><a href="http://thingsinjars.com/post/422/jquery-detach-scrollbars-plugin-/">jQuery Detach Scrollbars Plugin </a></p>
<p>tl;dr: I made a plugin: <a href="http://thelab.thingsinjars.com/detach-scrollbars/jquery.detach-scrollbar.min.js">jQueryDetach Scrollbars Plugin download [Zip &ndash; 1.4KB]</a></p>
<p>A design I recently worked on called for a scrollbar which only took up half the height of the area it was scrolling. Now, I'm not going to get into a discussion about scroll behaviour, accepted standards or user expectations - fascinating though that would be - instead, Here's a jquery plugin. </p> 

<p>The existing jQuery plugins I found that dealt with scrollbars created their own custom, themable bars. <a href="http://jscrollpane.kelvinluck.com/">jScrollpane</a>, for instance, gives you complete control over pretty much every aspect of the look and feel of the scrollbar. I figured this was too much for my needs, all I wanted was to be able to anchor the scrollbar to a given corner and change its height. <a href="http://thelab.thingsinjars.com/detach-scrollbar/">The resulting plugin</a> does just that. It even handles OS X Lion's disappearing scrollbars natively, too.</p> 

<h2>Usage</h2>
<p>Note: This currently only works on vertical scrolling and doesn't have a good jQuery setup and teardown. If I needed it more than once on a page, I'd have written it a bit more robustly so it could be used more than once. Maybe I'll leave that task as an exercise for the enthusiastic reader.</p>

<p>If you call the plugin on an element with a scrollbar (i.e. the element has height and contains content that overflows), it will duplicate the scrollbar using the standard browser scrollbar and get rid of the original one. In fact, in its default configuration, there's pretty much no difference between using the plugin and not using it.</p> 

<pre><code>$(element).detachScrollbar();</code></pre>

<p>It becomes more useful, however, when you pass in a couple of options. This example will move the scrollbar to the left of the content area:</p>
<pre><code>$(element).detachScrollbar({anchor : 'topleft'});</code></pre>

<p>You could leave the scrollbar on the right but shrink it downwards:</p>
<pre><code>$(element).detachScrollbar({anchor : 'bottomright', height : '50%'});</code></pre>

<p>The only behaviour of a standard scrollable area that isn't replicated by default is being able to use the mouse wheel to scroll while over the content area. If you want this behaviour (and you probably do), all you need to do is include the <a href="http://brandonaaron.net/code/mousewheel/docs">jQuery Mousewheel plugin</a> in your page. This script will recognise if it's available and enable the functionality.</p>

<h2>How it works</h2>
<p>The script creates a container div around the original scrollable content and sets that to <code>overflow:hidden</code> while setting the original area to <code>height:auto</code>. This means that the original scrollbar disappears. It then creates another invisible div the same height as the original content and wraps that in a div with <code>overflow-y:scroll</code>, this creates a scrollbar that looks exactly like the original one. Add in some clever event trickery to tie the scroll position of one to the scroll position of the other and we're done. We've replicated the original functionality but can now control the styles applied to the scrollbar completely separately from the original content. This means we can position it to the left or above, maybe add a 90&deg; CSS transform and have it look like a horizontal scrollbar, anything you like.</p>
<p>The plugin also incorporates &ldquo;Cowboy&rdquo; Ben Alman's <a href="http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth">scrollbar width plugin</a> to make sure we're matching dimensions on whatever platform this is used on.</p>

<p>The options that can be passed in are:</p>
<pre><code>internal: true / false (default: true)
autoposition: true / false (default: true)
anchor: 'topleft' / 'topright' / 'bottomleft' / 'bottomright' (default: 'topright')
height: Any CSS length (default '100%')</code></pre>

<h2>Advanced usage</h2>
<p>The <code>autoposition</code> option allows you to decide whether to let the plugin handle the layout (which you probably do for most cases) or whether you want to specify everything yourself using the provided classes as styling hooks.</p>

<p>The other option, <code>internal</code>, determines the DOM structure. Specifically, it says whether everything is contained within the one element or whether the scrollbar is separate. Specifying <code>internal: false</code> would allow you to put the scrollbar anywhere on your page. You could have all scrollbars set as <code>position: fixed</code> along the top of the page if you wanted. Not sure why you would but you could.</p>

<h2>Example and Download</h2>
<p><a href="http://thelab.thingsinjars.com/detach-scrollbar/">jQueryDetach Scrollbars Plugin</a></p>
<p><a href="http://thelab.thingsinjars.com/detach-scrollbar/jquery.detach-scrollbar.js">jquery.detach-scrollbars.js</a></p>      </div>
]]></description>
<pubDate>Fri, 09 Dec 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>You must be able to read before you get a library card</title>
<link>http://thingsinjars.com/post/416/you-must-be-able-to-read-before-you-get-a-library-card/</link>
<guid>http://thingsinjars.com/post/416/you-must-be-able-to-read-before-you-get-a-library-card/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-416">
        <p><a href="http://thingsinjars.com/post/416/you-must-be-able-to-read-before-you-get-a-library-card/">You must be able to read before you get a library card</a></p>
<p>I like JavaScript. JS. ECMAScript. Ol' Jay Scrizzle as nobody calls it.</p>

<p>I also like <a href="http://jquery.com/">jQuery</a>. jQ. jQuizzie. jamiroQuery. Whatever.</p>

<p>Ignoring the stoopid nicknames I just made up, did you notice how I referred to JavaScript and jQuery separately? I didn't say "I like JavaScript, there are some really great lightbox plugins for it" just the same as I didn't say "I wish there was a way to do indexOf in jQuery".</p>

<p>I'm regularly amazed at how many new (and some not-so-new) web developers either think they know JavaScript because they know jQuery or wish there was a way to do something in jQuery that they read about in an article about JavaScript. jQuery is a <em>library</em> written to make coding in JavaScript easier. It's made in JavaScript so you can say "jQuery is JavaScript" but only in the same way that "Simon is male". To confuse jQuery as all of JavaScript is the same as saying "Simon is all men" (don't worry, there's still only one of me).</p>

<p>For most web site or web app development, I do recommend using a library. Personally, I've used jQuery and <a href="http://www.prototypejs.org/">Prototype</a> extensively and decided I prefer jQuery. Libraries are designed to make coding faster and more intuitive and they can be a great productivity aid. You can get a lot more done quicker. There is a downside, however.</p>

<h2>Downside</h2>
<p>If you're doing what the library was intended to help with, great. Slide this panel up, pop open a modal window, scroll to the bottom of the page and highlight that header. Brilliant. The difficulties come when you're either trying to do something the library wasn't intended to do or something nobody's thought of before or you're just plain doing something wrong. If you are fluent in your library of choice but don't know the JavaScript underpinnings, your usual debugging tools can only help you so far. There will come a point where there's an impenetrable black-box where data goes in and something unexpected comes out. Okay, it's probably still data but it's unexpected data.</p>

<p>Don't let this point in the process be the discouragement. This is where the fun bit is.</p>

<h2>Learning to read</h2>
<p>Library authors are very clever groups of people. Often large groups. Reading through the unminified source of a library can be an awesomely educational experience as it's usually the culmination of many years best practice. If you want a nice introduction to some of the cool things in jQuery, for instance, check out these videos from <a href="http://paulirish.com/">Paul Irish</a>:</p>

<ul><li><a href="http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/">http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/</a></li>
<li><a href="http://paulirish.com/2011/11-more-things-i-learned-from-the-jquery-source/">http://paulirish.com/2011/11-more-things-i-learned-from-the-jquery-source/</a></li></ul>

<p>I've dug around in jQuery many, many times to try and figure out why something does or doesn't do what it should or shouldn't. The most detailed investigation was probably <a href="http://thingsinjars.com/post/371/investigating-ies-innerhtml/">Investigating IE's innerHTML</a> during which nothing was solved but I found out some cool stuff.</p>

<h2>Learning to write</h2>
<p>The best way to get your head around libraries is to write your own. Yes, there are literally millions of them (not literally) out there already but you don't need to aim for world dominance, that's not the point of writing your own. Start simply, map the dollar symbol to <code>document.getElementById</code>. Done. You've written a tiny library. </p>

<pre><code>function $(id){ 
    return document.getElementById(id);
}</code></pre>

<p>Now you can add some more stuff. Maybe you could check to see if the thing passed to the $ is already an element or if it's a string. That way, you could be a bit more carefree about how you pass things around.</p>

<pre><code>function $(id){ 
  if(id.nodeType) {
    return id;
  } else {
    return document.getElementById(id);
  }
}</code></pre>

<p>Add in a couple of AJAX methods, some array manipulation and before you know it, you've got a full-blown web development toolkit. </p>

<p>If you're wanting a boilerplate to start your library off, I recommend Adam Sontag's <a href="https://github.com/ajpiano/boilerplate-boilerplate">Boilerplate Boilerplate</a>.</p>

<h2>Here's your Library Card</h2>
<p>By now, you've rooted around in the jQuery undergrowth, dug through some of Moo's AJAX and pulled apart Prototype's string manipulation. You've written your own mini library, gotten a bit frustrated and wished you had a community of several thousand contributors to make it more robust. Now you're ready to start getting irked every time someone on <a href="http://forrst.com">Forrst</a> asks if there's a jQuery plugin for charAt. Enjoy.</p>
<p>This article is modified from a chapter in a book <a href="http://www.phenotypic.co.uk">Andrew</a> and I were writing a couple of years ago about web development practical advice. Seeing as we both got too busy to finish it, I'm publishing bits here and there. If you'd like to see these in book form, let me know.</p>      </div>
]]></description>
<pubDate>Thu, 04 Aug 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Vendor-prefix questions</title>
<link>http://thingsinjars.com/post/414/vendor-prefix-questions/</link>
<guid>http://thingsinjars.com/post/414/vendor-prefix-questions/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-414">
        <p><a href="http://thingsinjars.com/post/414/vendor-prefix-questions/">Vendor-prefix questions</a></p>
<p>There's something that's always niggled me about vendor-specific prefixes on CSS.</p>


<h2>Vendor prefix background</h2>
<p>Just in case you don't know about vendor prefixes, there's a good summary on <a href="http://www.alistapart.com/articles/prefix-or-posthack/">A List Apart</a>.</p>


<p>Best practice dictates that you should <a href="http://www.456bereastreet.com/archive/201009/remember_non-vendor-prefixed_css_3_properties_and_put_them_last/">always include non-prefixed properties last</a>. This is so that when the property does become standard and the browser implements the non vendor-prefix version, it will use the standard rule as it comes later in the stylesheet than the prefixed one. The thing that has been bugging me is the assumption that the agreed standard version produces the same or better results than the prefixed one.</p>

<h2>A convulted and completely made-up example</h2>
<p>Imagine you have a paragraph:</p>
<pre><code rel="html">&lt;p&gt;Made-up text.&lt;/p&gt;</code></pre>
<p>And you want it to have a white border with rounded corners. I'm fully aware you now don't need the vendor prefixes here but bear with me.</p>
<pre><code rel="css">p {
  border:1px solid white;
  -webkit-border-radius:5px;
  -moz-border-radius:5px;
  -ms-border-radius:5px;
  -o-border-radius:5px;
  border-radius:5px;
}</code></pre>
<p>In this scenario, the non-prefixed border-radius hasn't been implemented by any browser but you're following best practice so you include the values matching the current specification. Okay, now imagine that for Webkit's implementation of <code>-webkit-border-radius</code>, they decided that the radius value was actually to be divided by two. No problem, you can include the required value for Webkit. Again, not a real example but stick with me.</p>
<pre><code rel="css">p {
  border:1px solid white;
  -webkit-border-radius:10px;
  -moz-border-radius:5px;
  -ms-border-radius:5px;
  -o-border-radius:5px;
  border-radius:5px;
}</code></pre>
<p>You launch the site and send it out into the world.</p>
<p>Six months later, the standard is set, it turns out developers agree on Webkit's implementation. It becomes standard to double your radius value. A month after that, browsers start recognising the non-prefix version of the rule and rendering with the new standard. At this point, webkit, moz, ms and o are all rendering wrong because they are ignoring their vendor-specific implementation and using the non-prefixed standard. Even though webkit currently has the right value, it's being overwritten. If the rules had been included the other way round, they'd still be rendering the same as they were.</p>
<pre><code rel="css">p {
  border:1px solid white;
  border-radius:5px;
  -webkit-border-radius:10px;
  -moz-border-radius:5px;
  -ms-border-radius:5px;
  -o-border-radius:5px;
}</code></pre>
<p>Eventually,support for the prefixed version will be dropped and the browsers will only use the standard but that will be a little way down the line and gives you more time to correct your code or your client's code or wherever the code happens to be. Basically, prefix-last order buys the developer more time to correct any potential issues. I know that by using the vendor-prefixed rules, the developer is implicitly accepting the fact that they are using experimental properties which could change but in this scenario, it is not the prefixed properties that change but the non-prefixed one.</p>

<p>The reason I chose border-radius here is just because it was easier that typing up an example that might actually happen in real-life involving gradients or masks.</p>


<h2>Open to suggestions</h2>
<p>I'm open to any explanation as to why this scenario might never happen or comments on how I've misunderstood something.</p>      </div>
]]></description>
<pubDate>Fri, 29 Jul 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Feed the RSS</title>
<link>http://thingsinjars.com/post/413/feed-the-rss/</link>
<guid>http://thingsinjars.com/post/413/feed-the-rss/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-413">
        <p><a href="http://thingsinjars.com/post/413/feed-the-rss/">Feed the RSS</a></p>
For no real reason and definitely not to prove once again that RSS isn't dying, I just thought I'd write about a couple of the nice bits about the RSS feeds on this site so that readers could get the maximum amount of awesome per unit of blog.

There's a handy trick you can do with the feeds if you don't want posts from every category. You can subscribe to an individual category by using the link <a href="http://thingsinjars.com/rss/categoryname">http://thingsinjars.com/rss/categoryname</a>. 

But that's not all.

If, for instance,  you like the JS and CSS stuff but can't stand the rest, just list the categories you want with a plus and you'll get those feeds combined and nothing else. Like this: <a href="http://thingsinjars.com/rss/js+css">http://thingsinjars.com/rss/js+css</a>. Nifty, eh?

Also, the RSS link changes depending on which category you're in.      </div>
]]></description>
<pubDate>Wed, 27 Jul 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Multi-user pages</title>
<link>http://thingsinjars.com/post/412/multi-user-pages/</link>
<guid>http://thingsinjars.com/post/412/multi-user-pages/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-412">
        <p><a href="http://thingsinjars.com/post/412/multi-user-pages/">Multi-user pages</a></p>
<p>Whenever I'm away from home, my usual stream of random <a href="http://thingsinjars.com/ideas/">ideas</a> tends to become more focused on projects involving sharing. Usually something about creating a connection between people where the interaction point is the Internet. This is what first inspired the now defunct <a href="http://thingsinjars.com/post/135/monkeying-about-with-xul/">MonkeyTV</a> project back in 2007 or <a href="http://noodler.net/">noodler.net</a> in 2008 &ndash; both created while I was living in Tokyo as ways to connect to people back in Edinburgh.</p>

<p>Until the beginning of August, I'm in Berlin finding somewhere to live while Jenni and Oskar are in Edinburgh packing up our flat (although, I'm not entirely sure Oskar is doing much more than drooling over packing boxes). The result of this is that I started to wonder about how to best show Jenni some of the flats I'm looking at remotely. What I figured I wanted was a way for us both to be looking at the same web page and for each of us to be able to point out things to the other. I tidied up my idea and posted it to the <a href="http://byideas.co.uk/i88">Made By Ideas</a> site hoping that someone else would run off and make it so I could focus on apartment hunting.</p>

<p>The inevitable happened, I couldn't let it lie:</p>

<p><a href="javascript:void(things_z=document.body.appendChild(document.createElement('script')));void(things_z.language='javascript');void(things_z.type='text/javascript');void(things_z.src='http://thelab.thingsinjars.com/shared/shared.js');void(things_z.id='things');">Multi-user page</a> (installable bookmarklet).</p>

<p>If you install that bookmarklet by draggin&rsquo; it to your bookmarks bar then launch it anywhere, your cursor position and how far you've scrolled the page will be sent to anyone else viewing the same page who has also launched it. If you launch it on this page just by clicking it just now, you'll see cursors from other people reading this post who've also clicked it.</p>

<h2>Technical</h2>
<p>This is built in <a href="http://nodejs.org/">node.js</a> with <a href="http://socket.io/">socket.io</a>.</p>

<p>It heavily reuses <a href="http://jeffkreeftmeijer.com/2010/experimenting-with-node-js/">Jeff Kreeftmeijer's multiple user cursor experiment</a> but updated to use socket.io v0.7. I also used the socket.io 'rooms' feature to contain clients to a given window.location.href so that it could be launched on any page and interactions would only appear to users on that same page. I also removed the 'speak' feature to simplify things. I'm planning on talking via Skype when I'm using it. In theory, mouse events other than cursor coordinates and scroll could be shared &ndash; keyboard input, clicks, selects. </p>

<p>The day after I built this, <a href="http://www.wait-till-i.com/">Christian Heilmann</a> pointed out <a href="https://twitter.com/#!/codepo8/status/91164622614315010">on twitter</a> a different solution to the same problem. <a href="http://mirror.colorstudy.com/">Browser Mirror</a> uses the same technology (node + websockets) but instead of passing cursor positions, it passes the entire DOM of the page from the instigator's computer to their node relay and then out to any invited viewers. This approach gets round a lot of the problems and is probably a more robust solution, all in all. They also have an integrated chat feature.</p>

<h2>Warning</h2>
<p>The server side is running on a borrowed VPS. It's not even been daemonised using Forever so it might fall over and not come back up. Don't rely on this for anything, just think of it as a point of interest.</p>

<h2>The Code</h2>
<p>I'm not really going to do any further development with it but for interest, here's the node.js server, almost entirely <a href="http://jeffkreeftmeijer.com/2010/experimenting-with-node-js/">Jeff Kreeftmeijer's</a> work but updated for the latest socket.io</p>
<pre><code>var sys = require('sys'),
    http = require('http'),
    io = require('socket.io').listen(8000),
    log = sys.puts;

io.sockets.on('connection', function (socket) {
	socket.on('set location', function (name) {
	    socket.set('location', name, function () { socket.emit('ready'); });
		socket.join(name);
	});
	socket.on('message', function (request) {
		socket.get('location', function (err, name) {
			if(request.action != 'close' && request.action != 'move' && request.action != 'scroll') {
				log('Invalid request:' + "\n" + request);
				return false;
			}
			request.id = socket.id;
			socket.broadcast.to(name).json.send(request);
		});
	});
	socket.on('disconnect', function () {
		socket.broadcast.json.send({'id': socket.id, 'action': 'close'});
	});
});</code></pre>

<p>And here's a bit of the client-side JS that I modified to connect via socket.io v0.7 (again, modified from Jeff Kreeftmeijer's):</p>
<pre><code>
var socket = io.connect('http://yourserver.com', {port: 8000}),
socket.on('connect', function() {
	socket.emit('set location', window.location.href);
	socket.on('message', function(data){
    if(data['action'] == 'close'){
      $('#mouse_'+data['id']).remove();
    } else if(data['action'] == 'move'){
      move(data);
    } else if(data['action'] == 'scroll'){
			clearTimeout(noscrolltimeout);
			disabled = true;
      scroll(data);
			noscrolltimeout = setTimeout('disabled = false;',2000);
    };
  });
});</code></pre>

<p>If you'd like to snoop around the code more, it's all available on the lab: <a href="http://thelab.thingsinjars.com/shared/">Multi-user pages</a></p>

<p>Props to <a href="http://www.phenotypic.co.uk/">Andrew</a> for letting me use his server, by the way. It was enough hassle having to learn node for this little experiment, he saved me from having to build my own.</p>      </div>
]]></description>
<pubDate>Mon, 18 Jul 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Workflow. The flow. Of work.</title>
<link>http://thingsinjars.com/post/408/workflow-the-flow-of-work/</link>
<guid>http://thingsinjars.com/post/408/workflow-the-flow-of-work/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-408">
        <p><a href="http://thingsinjars.com/post/408/workflow-the-flow-of-work/">Workflow. The flow. Of work.</a></p>
<h2>How to actually work</h2>
<p>Don&rsquo;t tell anyone (particularly not your clients and especially not my clients) but making websites is really very easy. Don't make it harder by deliberately hindering yourself. You should always try to travel the shortest distance between &ldquo;amends needs done&rdquo; and &ldquo;amend is done&rdquo;. Again, I hear a &ldquo;Pah!&rdquo; in the distance, &ldquo;Well, that&rsquo;s obvious.&rdquo;, but is it? Are you sure you&rsquo;re ‘Being all you can be&rsquo;?</p>
<h2>The shortest distance</h2>
<p>Okay, picture the scene: you've run out of socks. You need to put on a load of washing. The washing is in a pile in the corner of the room. You hunch over, pick up all the socks, pants, t-shirts and walk, waddle and totter to the washing machine. As you walk, you drop a sock and bend down to pick it up, dropping another. You recover that one and another falls. Eventually, you make it to the washing machine after a few minutes, put everything in, throw in some powder and set it going. As you head back to your bedroom, you spot three more socks that you missed. Darn.</p>
<p>Okay, picture the scene: you've run out of socks. You need to put on a load of washing. Fortunately, every time you took your socks off, you put them straight in the washing machine. You wander to the kitchen, put in the powder and switch it on. Done.</p>
<p>Any time you try to do anything, the more steps involved between intention and completion, the more likely it is to go wrong. Whether the intention is 'wear clean socks' or 'update this website', if you can do it in a handful of steps, you'll make fewer mistakes than if you have to do it in a hunched-over armful.</p>
<h2>Workflow. The flow. Of Work.</h2>
<p>The next time you're making an amend somewhere, watch yourself. Watch which applications you jump between. Don't just make your changes, pay attention to how you do them. Are you jumping between text editor and FTP client? Text editor and web browser? FTP and Subversion? Just take a few minutes to think about which steps you might be able to miss out. For instance, if you use Textmate and Transmit, you can set up DockSend so that pressing ctrl-shift-f then 2 will upload the file you currently have open to the same place on the server. You can now change the editor↔FTP↔browser cycle to editor↔browser.</p>
<h2>However...</h2>
<p>Seamless does not imply flawless. Don't be tempted to simplify to the stage where you don't need any interaction between making a change and the change being live. If you rely on the fact that your changes 'just happen', you might be tempted not to check. That's the point at which they don't 'just happen'.</p>
<p>This article is modified from a chapter in a book <a href="http://www.phenotypic.co.uk">Andrew</a> and I were writing a couple of years ago about web development practical advice. Seeing as we both got too busy to finish it, I'm publishing bits here and there. If you'd like to see these in book form, let me know.</p>      </div>
]]></description>
<pubDate>Fri, 28 Oct 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Testing</title>
<link>http://thingsinjars.com/post/406/testing/</link>
<guid>http://thingsinjars.com/post/406/testing/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-406">
        <p><a href="http://thingsinjars.com/post/406/testing/">Testing</a></p>
<h2>The web is a visual medium. Well, mostly.</h2>
<p>There's no better way to test a visual medium than by looking at it. Look at your site in as many browsers as you can. If you've already got as many browsers installed on your development computer as you can fit, get another computer and install some more. Either that or run a Virtual Machine.</p>


<h2>Definition: Virtual Machine (VM)</h2>
<p>Applications like VirtualBox, VMWare or Parallels allow you to run an entire computer within your computer. It is a self-contained system that doesn't interact with your own machine meaning you can have IE6 installed on one VM, IE7 on another and IE8 on a third. All running in a window on your iMac. Shiny.</p>


<p>If you can't do that easily, you could use one of the growing number of browser testing services. These are server rooms packed with computers running Virtual Machines and automated systems to which you supply a URL, wait a few moments and get shown an image (or several hundred images) showing your URL in different browsers on different platforms. Some of the more sophisticated services allow you to scroll down a long page or specify different actions, text entry or mouse events you want to see triggered. These services can be exceptionally useful when it comes to developing HTML e-mails as there are some rare and esoteric e-mail clients out in the wild. <a href="http://litmus.com/">Litmus</a> does an excellent job at virtualised testing for HTML e-mails. On that note, the Campaign Monitor <a href="http://www.campaignmonitor.com/templates/">library of free HTML e-mail templates</a> is a great place to start, learn and possibly finish when working on an HTML e-mail.</p>

<p>There is also a place for automated testing for some things. Recently, there has been a bit of a movement away from validating code as the purpose of web development is not to make it 'check a box' on a merely technical level, it is to get the message across via the design however possible. However, validation is still the best and easiest way to check your syntax. Syntax errors are still the main cause for mistakes appearing in your web sites and are the easiest thing to fix. Don't assume IE is wrong. Again, if you're keen on HTML e-mails, here's a <a href="http://litmus.com/blog/validating-html-for-email">great post on the Litmus blog</a>.</p>

<p>This article is modified from a chapter in a book <a href="http://www.phenotypic.co.uk">Andrew</a> and I were writing a couple of years ago about web development practical advice. Seeing as we both got too busy to finish it, I'm publishing bits here and there. If you'd like to see these in book form, let me know.</p>      </div>
]]></description>
<pubDate>Fri, 09 Sep 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Don’t be seduced by the drag-and-drop side</title>
<link>http://thingsinjars.com/post/405/dont-be-seduced-by-the-drag-and-drop-side/</link>
<guid>http://thingsinjars.com/post/405/dont-be-seduced-by-the-drag-and-drop-side/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-405">
        <p><a href="http://thingsinjars.com/post/405/dont-be-seduced-by-the-drag-and-drop-side/">Don’t be seduced by the drag-and-drop side</a></p>
<p>You don&rsquo;t have to be a survivor of the vi and Emacs holy wars to appreciate the beauty of fully hand-crafted code. There was a bit of attention a couple of weeks ago on the soon-to-be-launched <a href="http://muse.adobe.com/">Adobe Muse</a> which lets you &ldquo;Design and publish HTML websites without writing code&rdquo;. If you want to be a kick-ass developer, you must realise that tools like this aren't designed for you. They're designed for people who want to do what you can do but either don't have the time or the inclination to learn how. Although drag 'n' drop application do lower the barrier to entry for creating a website, there is still a need for web developers to know exactly what's going on in their pages.</p>

<p>I'm not saying that there will never be a time when visual design can be automatically translated into as good a product as a hand-crafted site, I'm just saying it&rsquo;s not yet.</p>

<p>In much the same way as with JavaScript (See &ldquo;<a href="http://thingsinjars.com/post/416/you-must-be-able-to-read-before-you-get-a-library-card/">You must be able to read before you get a library card</a>&rdquo;), building your HTML using that extra level of abstraction might work for almost every situation but will eventually leave you stuck somewhere you don&rsquo;t want to be. By all means, pimp up your text editor with all manner of handy tools, shortcuts and code snippets but make sure you still know exactly what each bit of mark up means and does. If you structure your code well (more on that in a later post), your natural feel for the code will be as good a validator as anything automated (by which I mean prone to errors and worth double-checking).</p>

<p>Learn the keyboard shortcuts. If you learn nothing else from this, learn the importance of keyboard shortcuts. You might start off thinking you'll never need a key combination to simply swap two characters around but one day, you'll find yourself in the middle of a functino reaching for ctrl-T.</p>

<p>Also, there is no easy way to tell if a text editor is fit for you until you have tried it, looking at screenshots won&rsquo;t work. You don't need to build an entire project to figure out whether or not you're going to get on with a new text editor, just put together a couple of web pages, maybe write a jQuery plugin. Do the key combinations stick in your head or are you constantly looking up the same ones again and again? Do you have to contort your hand into an unnatural and uncomfortable claw in order to duplicate a line?</p>

<p>The final thing to cover about text editors is that it's okay to pay for them. Sure, we all love free software. &ldquo;Free as in pears <em>and</em> free as in peaches&rdquo; (or whatever that motto is) but there are times when a good, well-written piece of software will cost money. And that's okay. You're a web developer. You are going to be spending the vast proportion of your day using this piece of software. If the people that made it would like you to spend $20 on it, don't instantly balk at the idea. Think back to the idea of web developers as artisan craftsmen. You're going to be using this chisel every day to carve out patterns in stone. Every now and then, you might need to buy your own chisel.</p>

<p>This article is modified from a chapter in a book <a href="http://www.phenotypic.co.uk">Andrew</a> and I were writing a couple of years ago about web development practical advice. Seeing as we both got too busy to finish it, I'm publishing bits here and there. If you'd like to see these in book form, let me know.</p>      </div>
]]></description>
<pubDate>Mon, 29 Aug 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Go on, google me.</title>
<link>http://thingsinjars.com/post/403/go-on-google-me/</link>
<guid>http://thingsinjars.com/post/403/go-on-google-me/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-403">
        <p><a href="http://thingsinjars.com/post/403/go-on-google-me/">Go on, google me.</a></p>
<p>A little while back when I was still job-hunting, I saw an interesting position come up with <a href="http://f-i.com/">FI</a> in Stockholm. They're the agency behind things like Google's <a href="http://www.20thingsilearned.com/">20 things I learned about browsers and the web</a>. They were looking for a Web Producer to be clever and creative and innovative and insightful and all the usual things Web Producers are. I decided to apply but with such a high-profile agency, I figured my application had better be something appropriately clever and creative to get noticed.</p>

<p>I spent a couple of weeks tweaking key-words in my site to manipulate search results for the phrase "Awesomest Web Producer". I then used <a href="http://moo.com">Moo</a> to print up a postcard featuring a google search box with that phrase entered and the mouse cursor hovering over the "I'm feeling lucky" button (this trick doesn't work quite so well now that Google have launched Google Instant).</p>


The postcard application
<a href="http://thingsinjars.com/uploaded/images/expanded/google.png" rel="lightbox"><img src="http://thingsinjars.com/uploaded/images/google.png" alt="Awesomest Web Producer"></a>


<p>I posted the card off to them with the job reference number on the back and the words "My application" handwritten. No name, no signature, no contact details. If the scheme worked, they'd find me, proving the value of taking me on. That was my thinking, anyway. To be honest, once I'd sent off the postcard, I figured that was the end of it. It was a cocky, big-headed move and probably wouldn't work.</p>

<p>It did work. Kinda. It worked perfectly on a technical level, at least: you could enter the phrase, hit the button and land on my CV site. If you didn't hit "I'm feeling lucky", you were still presented with a page of search results, each about me, my career history and some of my projects. It also worked to get FI to contact me. I went through a few stages of the recruitment process before we parted ways. I never did find out exactly why but I wasn't quite 'the right fit'.</p>

<p>Of course, if I'd gone there, I wouldn't be starting a kick-ass job with Nokia next week.</p>      </div>
]]></description>
<pubDate>Mon, 04 Jul 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Torch</title>
<link>http://thingsinjars.com/post/401/torch/</link>
<guid>http://thingsinjars.com/post/401/torch/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-401">
        <p><a href="http://thingsinjars.com/post/401/torch/">Torch</a></p>
<h2>Concept</h2>
<p>Another proof-of-concept game design prototype. This is kind of a puzzle game. Ish. It's mostly a simple maze game but one in which you can't see the walls. You can see the goal all the time but you are limited to only being able to see the immediate area and any items lit up by your torch. You control by touching or clicking near the torch. The character will walk towards as long as you hold down. You can move around and it'll follow.</p>

<p><a href="http://apps.angryrobotzombie.com/torch/">Torch v0.1</a></p>

<p>The first 10 levels are very easy and take practically no time at all. After that, they get progressively harder for a while before reaching a limit (somewhere around level 50, I think). The levels are procedurally generated from a pre-determined seed so it would be possible to share high scores on progression or time taken without having to code hundreds of individual levels. </p>

<p>Items that could be found around the maze (but aren't included in this prototype) include:</p>

<ul>
<li>Spare torches which can be dropped in an area and left to cast a light</li>
<li>Entrance/exit swap so that you can retrace your steps to complete the level </li>
<li>Lightning which displays the entire maze for a few seconds (but removes any dropped torches)</li>
<li>Maze flips which flip the maze horizontally or vertically to disorient you.</li>
</ul>

<p>I worked on this for a few months (off and on) and found it to be particularly entertaining with background sound effects of dripping water, shuffling feet with every step, distant thunder rumbling. It can be very atmospheric and archaeological at times.</p>


Half-way through a level, two torches dropped
<img src="http://thingsinjars.com/uploaded/images/maze.png" alt="Torch, the game">


<h2>Slightly technical bit</h2>
<p>The game loop and draw controls are lifted almost line-for-line from this <a href="http://dev.opera.com/articles/view/creating-pseudo-3d-games-with-html-5-can-1/">Opera Dev article on building a simple ray-casting engine</a>. I discarded the main focus of the article - building a 3D first-person view - and used the top-down mini map bit on its own. The rays of light emanating from the torch are actually the rays cast by the engine to determine visible surfaces. It's the same trick as used in <a href="http://en.wikipedia.org/wiki/Wolfenstein_3D">Wolfenstein 3D</a> but with fewer uniforms. It's all rendered on a canvas using basic drawing functionality.</p>

<p>The audio is an interesting, complicated and confusing thing. If I were starting again, I'd look at integrating an existing sound manager. In fact, I'd probably use an entire game engine (something like <a href="http://impactjs.com/">impact.js</a>, most likely) but it was handy to remember how I used to do stuff back in the days when I actually made games for a living. Most of all, I'd recommend not looking too closely at the code and instead focusing on the concept.</p>

<h2>Go, make.</h2>
<p>As with <a href="http://thingsinjars.com/post/390/knots/">Knot</a> from my previous blog post, I'm not going to do anything with this concept as I'm about to start a big, new job in a big, new country and I wanted to empty out my &lsquo;To do&rsquo; folder. The code's so scrappy, I'm not going to put it up on GitHub along with my other stuff, I seriously do recommend taking the concept on its own. If you are really keen on seeing the original code, it's all unminified on the site so you can just grab it from there.</p>

<p>The usual rules apply, if you make something from it that makes you a huge heap of neverending cash, a credit would be nice and, if you felt generous, you could always buy me a larger TV.</p>

<p><a href="http://apps.angryrobotzombie.com/torch/">Torch v0.1</a></p>      </div>
]]></description>
<pubDate>Mon, 11 Jul 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Knots</title>
<link>http://thingsinjars.com/post/390/knots/</link>
<guid>http://thingsinjars.com/post/390/knots/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-390">
        <p><a href="http://thingsinjars.com/post/390/knots/">Knots</a></p>
<h2>Game design</h2>
<p>I had an idea around Christmas for a new game design. it was basically to be a single or multi-player game where you would tie knots in a piece of &lsquo;string&rsquo;. The single-player game would focus on discovering new patterns while the multi-player one would be a time-based challenge where each would tie a knot, pass it over to their opponent and the first to untie it would win.</p>

<p>I built a basic prototype and had some fun inventing a few interesting knots (my favourite being &lsquo;Yoda&rsquo;) but didn't get round to doing anything with it. As I'm tidying up all my projects before immigrating to Germany, I figured I should just go ahead and put this out into the world.</p>

<p><a href="http://apps.angryrobotzombie.com/knot/">Knot v0.1</a></p>

<h2>Slightly technical bit</h2>
<p>The system is built using an invisible 3x3 grid and 4 quadratic curves. The curves' start, control and end points are the centre of a tile. When you move a tile, it basically swaps position with the tile nearest where you drop it. This can also be done with multiple tiles simultaneously if you're on a multi-touch device. You can see the tiles if you enable debug mode. You can also switch between the two colour schemes it has at the moment.</p>


Yoda in Knot form
<img src="http://thingsinjars.com/uploaded/images/yoda.png" alt="Yoda Knot">


<p>The only addition I've made to it since Christmas was to add on a system to allow players to save knots back into the system. I've only built in 22 patterns so if you make a nice, interesting or funny one, give it a recognisable name (nothing too rude, please) and save it, it will then be available to everybody who plays with it. You can also set whether the pattern is to count as &lsquo;matched&rsquo; when rotated 90&deg;, 180&deg;, flipped vertically or flipped horizontally. Calculating the isomorphisms (when two knots look the same to the viewer but aren't necessarily the same to the computer) was probably the trickiest bit of the system.</p>

<h2>Go, make.</h2>
<p>If you're interested in taking the idea further, <a href="https://github.com/thingsinjars/Knot">grab the code from GitHub</a> and make something from it. The usual rules apply, if you make something from it that makes you a huge tonne of neverending cash, a credit would be nice and, if you felt generous, you could always buy me a larger TV.</p>

<p><a href="http://apps.angryrobotzombie.com/knot/">Knot v0.1</a></p>
      </div>
]]></description>
<pubDate>Mon, 27 Jun 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Forrst Podcast</title>
<link>http://thingsinjars.com/post/389/forrst-podcast/</link>
<guid>http://thingsinjars.com/post/389/forrst-podcast/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-389">
        <p><a href="http://thingsinjars.com/post/389/forrst-podcast/">Forrst Podcast</a></p>
Last year, I had an idea for a Web Development Podcast Breakfast Show. The idea was that I'd get up early-ish in the morning GMT, catch up on the overnight tech news and record a short, 15-minute-or-so podcast. By the time I had tidied it and uploaded, it'd still be early for the US so listeners over there would be able to listen to it over breakfast. There might even be a tie-in app which would automatically play it as an alarm clock. It was a great idea. 

The only downside was that recording, editing and uploading a podcast daily is a heck of a lot of work and requires a serious commitment. I managed to do an offline dry run of it for a week before I woke up, turned over and went back to sleep. It turns out the <em>only</em> downside is a major one.

Bearing that in mind, I have a lot of respect for the guys that run <a href="http://forrstpodcast.com">The Forrst Podcast</a>, <a href="http://www.mikefresh.com/">Mike Evans</a> and <a href="http://thekennethlove.com/">Kenneth Love</a>. True, they don't always manage to make the four-episodes-a-week they aim for but they do record more often than not. At the time of writing this, they've just publish episode 115 having been going for about 8 months. 

Last week, I got in touch with them and mentioned that if they ever wanted a guest presenter they should give me a shout. Being the nice fellas they are, less than 24 hours later, I was recording with them. They actually would have had me on the same day I got in touch but I was balancing a drooling, sleeping, slightly sickly Oskar on me at the time and he has a tendency to gunk up the keys if I'm too close to the computer.

Long story short, if you're interested in tech, design and development news on a more-or-less daily-ish basis, I recommend subscribing to the <a href="http://forrstpodcast.com/">Forrst Podcast</a>. And, of course, if you're looking for a sample to find out what it's like, I can only recommend <a href="http://forrstpodcast.com/post/6654163499/forrst-podcast-113-chair-talk-schema-org-eames">Episode 113</a> featuring a guest presenter who, hopefully, will be allowed back some day...


      </div>
]]></description>
<pubDate>Wed, 22 Jun 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Design Archive</title>
<link>http://thingsinjars.com/post/385/design-archive/</link>
<guid>http://thingsinjars.com/post/385/design-archive/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-385">
        <p><a href="http://thingsinjars.com/post/385/design-archive/">Design Archive</a></p>
<p>Along with (yet another) redesign, I decided to collect all my old blog designs together for posterity. The thing that surprised me is my own progression in design terms. I would still find it difficult to call myself a designer in any sense but I will admit that I'm a bit better now than I was back when I started this site.</p>

<p>Note: this is just a gallery of the previous designs for the blog incarnation of this site. The site itself existed for quite a while before that when it hosted my two webcomics “Things in Jars” and “<a href="http://thingsinjars.com/cartoons/last/">Scene & Herd</a>”.</p>

<p>These are all simply themes that were applied to the base CMS ‘Dooze’.</p>

<h2>Previous blog themes</h2>
<ul>
 <li><a href="http://thingsinjars.com/archive/thingsinjars-dooze.html">Dooze</a> (2007-2009)</li>
 <li><a href="http://thingsinjars.com/archive/thingsinjars-slate.html">Underwater Slate</a> (2009-2010)</li>
 <li><a href="http://thingsinjars.com/archive/thingsinjars-felt.html">Felt</a> (2010-2011)</li>
 <li><a href="http://thingsinjars.com/archive/thingsinjars-desk.html">Desk</a> (2011-?)</li>
</ul>

<p>It's also a bit odd that I made <a href="http://thingsinjars.com/archive/thingsinjars-dooze.html">this</a> while working at a design agency and <a href="http://thingsinjars.com/archive/thingsinjars-desk.html">this</a> while working for the Government.</p>      </div>
]]></description>
<pubDate>Tue, 21 Jun 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>HTML5 for Large Public Bodies</title>
<link>http://thingsinjars.com/post/382/html5-for-large-public-bodies/</link>
<guid>http://thingsinjars.com/post/382/html5-for-large-public-bodies/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-382">
        <p><a href="http://thingsinjars.com/post/382/html5-for-large-public-bodies/">HTML5 for Large Public Bodies</a></p>
<h2>Your country needs you...</h2>

<p>...to stand at the cutting edge of technology.</p>

<p>Sounds awfully impressive, don't you think?</p>

<p>There are quite a few regulations to bear in mind and comply with when developing a website for a Government organisation or any large public body. This has lead to a lot of sites being developed in a very defensive manner, ensuring safe compliance at the expense of a great and consistent user experience.</p>

<p>This video features a presentation about how large publicly-liable institutions should and can embrace the latest in web technologies without sacrificing standards. By embracing them, in fact.</p>

<p>The content of this was developed while planning and building the <a href="http://www.nms.ac.uk/">National Museums Scotland website</a> which launched last November. The messages presented are applicable to museums, galleries, swimming pools, councils, anywhere, really.</p>

<p>If you're a techie person in the cultural or government sector, you might find this useful in convincing others to take advantage of the latest cool (and useful) technologies.</p>

<h2>Video</h2>
<p><a href="http://vimeo.com/24436131">HTML5 for Large Public Bodies</a> from <a href="http://vimeo.com/madine">Simon Madine</a> on <a href="http://vimeo.com">Vimeo</a>.</p>

<h2>Links from the presentation</h2>
<ul>
<li><a href="http://remysharp.com/2010/10/08/what-is-a-polyfill/">PolyFills</a></li>
<li><a href="http://www.netmagazine.com/features/making-html5-and-css3-work-polyfills-and-shims">.NET magazine article</a></li>
<li><a href="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills">(Almost) complete list of polyfills</a></li>
<li><a href="http://diveintohtml5.org/">Dive into HTML5</a></li>
<li><a href="http://html5boilerplate.com/">HTML5 Boilerplate</a></li>
<li><a href="http://www.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a></li>
<li><a href="http://html5doctor.com/">HTML5 Doctor</a></li>
<li><a href="http://alpha.gov.uk/">AlphaGov</a></li>
</ul>

<h2>Slideshow</h2>
<p>The source for the slides is <a href="http://thingsinjars.com/widgets/html5-presentation/">available online</a> although it's mostly webkit-friendly. I realise the irony of a presentation about cross-platform HTML5 not being a great example itself of that but it does degrade adequately. If I get the time in the future, I'll tidy it up. An actual good (and relevant) example of cross-platform web technologies is the <a href="http://www.nms.ac.uk/">National Museums Scotland website</a> itself which performs fantastically across all manner of platforms.</p>      </div>
]]></description>
<pubDate>Tue, 31 May 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Instant art</title>
<link>http://thingsinjars.com/post/381/instant-art/</link>
<guid>http://thingsinjars.com/post/381/instant-art/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-381">
        <p><a href="http://thingsinjars.com/post/381/instant-art/">Instant art</a></p>
I love making silly little digital toys. If I were more confident at talking waffle, I'd call them art and get a government grant to pursue the possibilities presented in projects integrating off and online expression and interaction and blah, blah, blah.

Anyway.

I took my '<a href="http://thingsinjars.com/post/294/art-maker-1k/">Automatic Tumblr Art Maker</a>' from last year and combined it with the hot new thing in town – <a href="http://instagr.am/">Instagram</a> – to make some kind of comment about the inherent nature of technology to remove the individuality from a composition and to put another barrier between the intention and reception. Or something. I dunno. It randomly generates a pseudo-meaningful statement and puts it on top of a randomly selected recent Instagram photo. It makes a new one every 15 seconds or you can click to generate one if you prefer your ironic art on demand. 

I've also added a couple of nice little extras to it: the tweet button in the bottom right will let you share a link to the exact combination of image and statement you're looking at so if you find a particularly poignant/ironic/idiotic one, you can share it. Also, on the off-chance you fancy using it as a screensaver, making it fullscreen will hide that tweet button so as not to get in the way of The Art.

Go, make ironic <a href="http://thelab.thingsinjars.com/insta-art.html">Insta-art</a>.      </div>
]]></description>
<pubDate>Mon, 30 May 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Psychopathic megalomaniac vs Obsequious sycophant?</title>
<link>http://thingsinjars.com/post/380/psychopathic-megalomaniac-vs-obsequious-sycophant/</link>
<guid>http://thingsinjars.com/post/380/psychopathic-megalomaniac-vs-obsequious-sycophant/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-380">
        <p><a href="http://thingsinjars.com/post/380/psychopathic-megalomaniac-vs-obsequious-sycophant/">Psychopathic megalomaniac vs Obsequious sycophant?</a></p>
<h2> - or - </h2>
<h2>Tabs vs Spaces?</h2>
<p>Which are you? Is there any middle ground?</p>

<p>In any modern, code-friendly text editor, you can set tab size. This means that one tab can appear to be as wide as a single space character or - more commonly - 2 or 4 spaces. It's even possible in some to set any arbitrary size so there's nothing stopping you setting tabs to be 30 spaces and</p>
<pre><code>format() {
                              your code() {
                                                            like;
                              }
                              this;
}</code></pre>

<p>However you do it, the point is that using tabs allows the reader personal preference.</p>

<p>Indenting your code using spaces, however, is completely different. A space is always a space. There's actually a simple conversion chart:</p>

<ul>
<li>1 = One</li>
<li>2 = Two</li>
<li>3 = Three</li>
<li>and so on.</li>
</ul>
<p>The fundamental difference here is that the person reading the code has no choice about how it's laid out. Tabs means you get to read the code how <em>you</em> want to, spaces means you read the code how <em>I</em> want you to. It's a subtle difference but an important one. </p>

<p>Space indenting is therefore perfectly suited to psychopathic megalomaniacs who insist their way is right while tab indenting is for obsequious sycophants who are putting the needs of others above themselves. Sure, there may be lots of grades in-between but why let moderation get in the way of a barely coherent point?</p>

<p>
Curiously, neither of these extremes feels a great need to comment their code. One sees no need as their code is for themselves and they already understand it, the other assumes that if they can understand it, its purpose is so obvious as to be trivial. Both are wrong here.</p>

<p>There's unfortunately no real middle ground here. Teams must agree amongst themselves what side of the fence they fall down on. It is entirely possible to set many text editors to automatically convert tabs to spaces or spaces to tabs on file save but if you're doing that, you'd better hope your favourite diff algorithm ignores white space otherwise version control goes out the window.</p>
<p>This article is modified from a chapter in a book <a href="http://www.phenotypic.co.uk">Andrew</a> and I were writing a couple of years ago about web development practical advice. Seeing as we both got too busy to finish it, I'm publishing bits here and there. If you'd like to see these in book form, let me know.</p>      </div>
]]></description>
<pubDate>Mon, 25 Jul 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Up-sticks</title>
<link>http://thingsinjars.com/post/379/up-sticks/</link>
<guid>http://thingsinjars.com/post/379/up-sticks/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-379">
        <p><a href="http://thingsinjars.com/post/379/up-sticks/">Up-sticks</a></p>
<p>So, after almost 2 years at National Museums Scotland, I'm moving on. And not just me, <a href="http://www.jennifuchs.com/">Jenni's</a> coming too (and Oskar, of course).</p>

<p>After delivering a <a href="http://www.netmagazine.com/news/html5-implemented-first-scottish-museums">kick-ass</a>, <a href="http://www.readwriteweb.com/archives/scotland_trailblazes_the_use_of_hmtl5_in_museums.php">ground-breaking</a> <a href="http://www.nms.ac.uk">website</a> and implementing some <a href="http://feastbowl.wordpress.com/2010/11/04/whats-that-new-shiny-thing/">cool shiny stuff</a>, I feel confident I can move on having made a bit of a difference. I initially took the job for two main reasons:</p>

<ol>
 <li>To bring advanced web-awesome to the cultural sector</li>
 <li>To prove my technical ability to myself at an international level</li>
</ol>

<p>I'm happy I've done that. The National Museums Scotland site looks a lot nicer above and below the surface than it did when I and the rest of the web team <a href="http://replay.web.archive.org/20090621101818/http://www.nms.ac.uk/">arrived in 2009</a>. Hopefully the systems and techniques I've put in place will ensure it stays at the front edge of the culture sector in terms of well-considered use of technology. The rest of the web team are still there, of course, and will continue to make cool stuff. I'll be satisfying my urge to build cool cultural stuff by providing the tech behind the various <a href="http://www.museum140.com/">Museum 140</a> projects.</p>
<p>You can read more about the first Museum 140 project ‘<a href="http://thingsinjars.com/post/378/archiving-tweets/">#MusMem</a>’ if you're interested.</p>

<p>The second reason is just as important. Working on a large national organisation website made me triple-check everything I wrote but my desire to build ‘Cool Stuff’ meant that I couldn't play it too safe. Favourable reviews from <a href="http://www.netmagazine.com/news/html5-implemented-first-scottish-museums">.NET magazine</a> and <a href="http://www.readwriteweb.com/archives/scotland_trailblazes_the_use_of_hmtl5_in_museums.php">ReadWriteWeb</a> suggest that we got the balance right.</p>

<h2>Personal projects</h2>
<p>In the last 12 months, I've also had a fair amount of success with my various personal tech projects – <a href="http://www.8bitalpha.com/">8bitalpha</a>, <a href="http://harmoniousapp.com">harmonious</a>, <a href="http://apps.angryrobotzombie.com/theelementals/">The Elementals</a>, <a href="http://apps.angryrobotzombie.com/whithr/">Whithr</a>, <a href="http://shelvi.st/">Shelvi.st</a> as well as being a featured case study on <a href="http://phonegap.com/">phonegap.com</a>. All of which have served to remind me I like the challenge of doing something beyond what I can already do.</p>

<h2>Where now, then?</h2>
<p>Now is the right time to step up from the top half of the First Division to somewhere in the middle of the Premier League (yeah, that's right, sport analogies). I'm going to be starting in July as Senior CSS Developer at Nokia in Berlin. I'll be working on the desktop interface for the services that used to be <a href="http://ovi.com/">ovi.com</a> (<a href="http://www.bbc.co.uk/news/technology-13409318">until a couple of weeks ago</a>) building interface frameworks and UI components.</p>

<p>Nokia have been going through a bunch of changes recently so I'm excited to be joining them now when there's a great opportunity to make a significant difference on a big scale.</p>

<p>I've only been to Berlin twice (an upcoming blog post will give more details about that) and, despite being German, Jenni's never been so it'll be an interesting move. Berlin does, however, have over 170 museums so if there's anywhere Jenni can perform <a href="http://www.jennifuchs.com/">her particular brand of museum-wizardry</a>, it'll be there. We've asked Oskar's opinion but he's not saying much. He's mostly drooling.</p>

<h2>Über-curricular activities</h2>
<p>I'm also hoping to give more conference talks and presentations (like <a href="http://thingsinjars.com/post/382/html5-for-large-public-bodies/">yesterday's</a>) as well as write more educational articles for this blog and others. I've got a few written that I've not had the chance to present anywhere so I might put them here at some point.</p>

<p>If you have any questions, throw <a href="http://twitter.com/intent/tweet?text=Oi.+blah+blah+blah" target="_blank">a tweet in my direction</a>.</p>      </div>
]]></description>
<pubDate>Thu, 02 Jun 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Archiving Tweets</title>
<link>http://thingsinjars.com/post/378/archiving-tweets/</link>
<guid>http://thingsinjars.com/post/378/archiving-tweets/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-378">
        <p><a href="http://thingsinjars.com/post/378/archiving-tweets/">Archiving Tweets</a></p>
<h2>Archiving Tweets - Technical</h2>
<p>Twitter has an amazing amount of data and there's no end to the number of ideas a coffee-fuelled mind can come up with to take advantage of that data. One of the greatest advantages of Twitter – its immediacy, its currency, its of-the-moment-ness – is, however, also one of the drawbacks. It is very easy to find out what people are thinking about now, yesterday or a few days ago but trying to find something from more than a week ago is surprisingly tricky. The standard, unauthenticated search only returns the last 7 days of results, beyond that, there's nothing. You can get around this by building custom applications which authenticate themselves correctly with Twitter and provide a level of traceability but that's quite tricky.</p>
<p>The easiest way to archive search results for your own personal use is actually surprisingly simple. Every search results page includes an RSS feed link<a href="http://thingsinjars.com/post/378/archiving-tweets/#foot_378_1" id="foot_378_a" class="footnote">1</a>. This will be updated everytime there are new results. Simply subscribe to this feed with a feed reader (<a href="http://reader.google.com">Google Reader</a> is simple and free) and your results will be archived permanently. This is great if you're searching for personal interest stuff but doesn't work so well if you want to share the results with the public.</p>
<p><a href="http://thingsinjars.com/post/378/archiving-tweets/#foot_378_a" id="foot_378_1" class="footnote">1</a> Note: The feed link only appears for searches performed on <a href="http://search.twitter.com">search.twitter.com</a>, <em>not</em> for searches performed via the standard web interface at <a href="https://twitter.com/#!/search/">https://twitter.com/#!/search/</a></p>
<p>This was the problem I was presented with when I was asked to build a tweet-archiving mechanism for <a href="http://www.museum140.com/">Museum140's</a> <a href="http://memories.museum140.com">Museum Memories (#MusMem)</a> project. Jenni wanted some kind of system that would grab search results, keep them permanently and display them nicely. I didn't want to create a fully OAuth-enabled, authenticated search system simply because that seemed like more work than should really be necessary for such a simple job. Instead, I went down the RSS route, grabbing the results every 10 minutes and storing them in a database using <a href="http://code.google.com/p/rssingest/">RSSIngest</a> by Daniel Iversen. The system stores the unique ID of each Tweet along with the time it was tweeted and the search term used to find it. The first time a tweet is displayed, a request is made to the Twitter interface to ask for all the details, not only of the tweet, but also of the user who tweeted it. These are then stored in the database as well. This way, we don't make too many calls to Twitter and we don't get blocked.</p>
<p>If you want your own Tweet Archive, I've <a href="https://github.com/thingsinjars/TweetArchiver">put the code on GitHub</a> for anyone to use. It requires PHP, MySQL and, ideally, a techie-type to set it up.</p>
<h2>Archiving Tweets - Non-technical</h2>
<p>With the technical side out of the way, we're left with the human issues to deal with. If you're automatically saving all results with a particular phrase, all a malicious person needs to do is include that phrase in a spam-filled tweet or one with inappropriate language and suddenly, it's on your site, too. If you aren't going to individually approve each tweet before it is saved, you must keep a vigilant eye on it.</p>
<p>The other thing which has turned out to be a problem is the Signal-to-Noise ratio. When we initially decided on the hashtag #MusMem, nobody else was using it. To use Social Media parlance, there was no hashtag collision.  The idea was to encourage people to use it when they wanted their memories stored in the MemoryBank. Unfortunately, it is now being used by anyone tweeting anything related to Museums and Memories. This is particularly troublesome at the moment as this month is International Museum month, one of the themes of which is ‘Memory’ (which is why we built the MemoryBank in the first place). This means that the permanent memories we want stored (the Signal) are getting lost in the morass of generic Museum Memories (the Noise). There is no way to solve this problem algorithmically. If we are to thin it down, we actually need to manually edit the several thousand entries stored.</p>
<p>If anyone can think of a solution to this issue, please let everybody know – the world needs you.</p>      </div>
]]></description>
<pubDate>Mon, 23 May 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Mini Zombie Pipe</title>
<link>http://thingsinjars.com/post/376/mini-zombie-pipe/</link>
<guid>http://thingsinjars.com/post/376/mini-zombie-pipe/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-376">
        <p><a href="http://thingsinjars.com/post/376/mini-zombie-pipe/">Mini Zombie Pipe</a></p>
<p>Here are some mockups I did for a game design last year.</p>

<ul class="gallery">
 <li><a href="http://thingsinjars.com/uploaded/images/expanded/zombiepipe-1.png" rel="lightbox[zom]"><img src="http://thingsinjars.com/uploaded/images/thumbs/zombiepipe-1.png"></a></li> <li><a href="http://thingsinjars.com/uploaded/images/expanded/zombiepipe-2.png" rel="lightbox[zom]"><img src="http://thingsinjars.com/uploaded/images/thumbs/zombiepipe-2.png"></a></li> <li><a href="http://thingsinjars.com/uploaded/images/expanded/zombiepipe-3.png" rel="lightbox[zom]"><img src="http://thingsinjars.com/uploaded/images/thumbs/zombiepipe-3.png"></a></li>
</ul>

<p>The general premise is a 2d physics game with multiple single-screen levels. When the level starts, you have a few seconds to rearrange whatever items/furniture/planks of wood you find lying around and place your hero somewhere on the screen. After the initial timer has run out, the pipe opens and hundreds or thousands of tiny zombies or robots (or robot zombies) pour into the level. You have to avoid being touched by them for 30 seconds, after which the level is cleared and you're on to the next level. The difficulty is in being able to quickly rearrange the furniture and choose your safe spot to prolong the time before they get you. As they are able to eat through most things, they would eventually get through.</p>

<p>There is the possibility for tweaks to the difficulty setting by changing the amount of available furniture, whether the protagonist can move mid-level, how many zombies there are, how small they are and so on.</p>

<p>At the time, I was too busy building <a href="http://www.smws.com/the-spirit-cellars/">The SMWS Spirit Cellars</a> and when i had time again, I started building <a href="http://apps.angryrobotzombie.com/theelementals">The Elementals</a> so I never came back to it. Looks like it could be a fun game, though.</p>      </div>
]]></description>
<pubDate>Fri, 13 May 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Travelling tales</title>
<link>http://thingsinjars.com/post/374/travelling-tales/</link>
<guid>http://thingsinjars.com/post/374/travelling-tales/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-374">
        <p><a href="http://thingsinjars.com/post/374/travelling-tales/">Travelling tales</a></p>
<p>When I was a young game designer wannabe living in St Andrews, I interviewed with a company in Manchester. For years, this was my biggest travel time:interview time ratio in that I got up shortly before 6, took a taxi, train and different train to get there by 1, had a 15 minute interview and then took two trains and a bus to get home by 11pm <a href="http://thingsinjars.com/post/374/travelling-tales/#interview_foot_1" class="footnote" id="interview_foot_a">1</a>.</p>

<p><a href="http://thingsinjars.com/post/374/travelling-tales/#interview_foot_a" class="footnote" id="interview_foot_1">1</a>Incidentally, the reason the interview only took 15 minutes was because the hiring manager delegated the responsibility of interviewing to the person he'd given the job to the week before. It was pretty much a case of “If you find out he's better than you, we'll give him the job instead...” Needless to say, I didn't get the job.</p>

<p>Now, the ratio is still unbeaten (31:1) but I have now definitely overtaken the basic numbers. I've recently travelled to Berlin twice to interview with Nokia's Ovi offices. I have since come to the conclusion that there is some mysterious force at work who really doesn't like me travelling through Schiphol. Note: I don't mean an omniscient being, I mean some actual <a href="http://archenemy.thingsinjars.com/">arch enemy</a>.</p>

<h2>Trip one</h2>
<p>Leaving on a Tuesday afternoon, I jumped on a plane at Edinburgh Airport to Amsterdam Schiphol then changed onto a plane to Berlin Tegel. I eventually arrived at my hotel in Schiphol around 11pm. After checking in, hanging up my interview shirt and scrubbing my face to get rid of the sheen of fellow air passengers, it was after midnight. Not the best prep for a full day of interviews, to be honest. The next morning, I got up, tried to partake of a German breakfast of rye bread and wurst, settled for a croissant and coffee and headed out into the -10°C weather. I won't go into the details of the interview process but by the end of the day, I'd been interviewed by 8 different people, drunk two pots of coffee myself and been told that I don't look particularly German. Not being German, I thought this statement was accurate.</p>
<p>I left the office, caught a taxi back to the airport and relaxed safe in the knowledge that I'd be back in Edinburgh in a few hours. An incorrect assumption, it would seem.</p>
<p>I arrived in plenty time to double-check the flights were all okay. There was even a flight to Schiphol before mine that some passengers were offered the chance to catch. I was relaxed, it was fine, I wasn't in a hurry, I'll catch the next one. Several hours later, I regretted that decision. The second flight was held in Schiphol before coming to Tegel due to broken air conditioning. By the time it had landed, turned round and let us board, I should have already been half way to Edinburgh and had missed the last connection. Boo.</p>
<p>One over night in a hotel later, I finally made it back to Edinburgh at 8am. Approximately 40 hours after I left. About 5.7:1.</p>
<h2>Trip two</h2>
<p>When it came to my second round of face-to-face interviews, I wasn't lucky enough to get an overnight stay, unfortunately. I had to get to Berlin and back in a day. The 2.45am start would have been bad enough under any circumstances but when you have a teething 5-month old and have generally been running on empty for the best part of 2 months, it very nearly killed me. Still...</p>
<p>Edinburgh to Schiphol – fine; Schiphol to Tegel – also fine. I arrived at the office only 3 minutes late for my 12 o’clock interview which isn't too bad after travelling about 800miles. Three hours of geek talk later, I'm back in the taxi on the way to Tegel, snapping photos out the taxi windows just to prove I was there. This time there's no delay at Tegel and I land in Amsterdam with about 2 hours to make it to my gate. I'm not exactly a relaxed traveller so I'm not the kind who can go via the airport pub, have a sit-down meal and casually meander to the gate in time to board. I'm more inclined to high-speed sprints and panicked departure board-scanning just to make sure I get to the gate several hours early so I can sit and do nothing. That's exactly what I did. I got to the gate in plenty of time to see the ‘Flight delayed’ ticker come up. Plenty of time to watch the ‘Estimated Departure’ go from 21:00 to 22:00 to 23:00 to 00:00. It was when it flashed ‘00:30’ it finally decided to stop.</p>
<p>I made it back to Edinburgh around 1am and got back to my house around 2.30am. Just in time to pick up Oskar as another night of painful teething screams started off, in fact. 7:1, this time.</p>      </div>
]]></description>
<pubDate>Mon, 13 Jun 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>I made this</title>
<link>http://thingsinjars.com/post/373/i-made-this/</link>
<guid>http://thingsinjars.com/post/373/i-made-this/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-373">
        <p><a href="http://thingsinjars.com/post/373/i-made-this/">I made this</a></p>
<p>Reading over recent posts, you may have gotten the impression that I'm a bit of a geek. I occasionally need to remind myself that I wasn't always so this weekend, I took a few hours and drew a picture of Oskar (the youngling).</p>
<p>Here are a few pictures I took of the drawing as it came along. Apologies for the quality not being great but my drawing studio isn't the best setup for photography.</p>

 <a href="http://thingsinjars.com/uploaded/images/oskar/1.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/1.jpg" alt="First sketch of Oskar"></a>
 Initial sketch of his head.


 <a href="http://thingsinjars.com/uploaded/images/oskar/2.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/2.jpg" alt="Second sketch of Oskar"></a>
 A bit more arm.


 <a href="http://thingsinjars.com/uploaded/images/oskar/3.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/3.jpg" alt="Third sketch of Oskar"></a>
 Some detail on the eyes to try and get a feel for the style.


 <a href="http://thingsinjars.com/uploaded/images/oskar/4.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/4.jpg" alt="Fourth sketch of Oskar"></a>
 Shading around the head and detail on the mouth.


 <a href="http://thingsinjars.com/uploaded/images/oskar/5.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/5.jpg" alt="Fifth sketch of Oskar"></a>
 Detail on his clothing.


 <a href="http://thingsinjars.com/uploaded/images/oskar/6.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/6.jpg" alt="Sixth sketch of Oskar"></a>
 Texture and depth added to the arm.


 <a href="http://thingsinjars.com/uploaded/images/oskar/7.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/7.jpg" alt="Seventh sketch of Oskar"></a>
 More depth to the clothes.


 <a href="http://thingsinjars.com/uploaded/images/oskar/8.jpg" rel="lightbox[oskar]"><img src="http://thingsinjars.com/uploaded/images/oskar/thumbs/8.jpg" alt="eighth sketch of Oskar"></a>
 Finished.
      </div>
]]></description>
<pubDate>Sun, 03 Apr 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Investigating IE's innerHTML</title>
<link>http://thingsinjars.com/post/371/investigating-ies-innerhtml/</link>
<guid>http://thingsinjars.com/post/371/investigating-ies-innerhtml/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-371">
        <p><a href="http://thingsinjars.com/post/371/investigating-ies-innerhtml/">Investigating IE's innerHTML</a></p>
<p>Be warned, this is a long and quite techy post that rambles a bit. It's about JS, <a href="http://jquery.com/" title="jQuery: The Write Less, Do More, JavaScript Library">jQuery</a>, IE and XML namespaces. Be careful.</p>
<p>I'm currently working on a tool which uses JS to parse an XML document and output it as JSON. Straightforward enough, you'd think. The issue I'm fighting against crops up when the XML tags have an arbitrary namespace. True enough, some of the files I'll be processing have this namespace defined at the top of the document but the tool has to be robust enough to cope when they don't.</p>
<p>To cut a long story short, IE6, IE7 and IE8 have an interesting attitude to innerHTML when the tags you are trying to insert have a namespace. IE9 seems to do the job as you'd expect. I've created some <a href="http://jsfiddle.net">jsFiddle</a> pages which try and identify the issues. They both use <a href="http://docs.jquery.com/Qunit" title="QUnit - jQuery JavaScript Library">QUnit</a> and the test code is included below.</p>
<h2>createElement nodeName vs get(0).nodeName</h2>
<p><a href="http://jsfiddle.net/thingsinjars/j4xJG/">View this on jsFiddle.net</a></p>
<p>I started off using jQuery to help identify this as the tool uses jQuery for the XML heavy-lifting. The two tests in this demo create elements in two different ways. First, we create the element using document.createElement and grab the nodeName then we use jQuery's constructor and use get(0) to grab the bare DOM element's nodeName. Also, in this first set of tests, we're creating non-standard elements.</p>
<pre><code class="prettyprint lang-js">
test("Compare elements without namespace", function() {
 var element1, element2;

 element1 = document.createElement('spud').nodeName;
 element2 = $('&lt;spud/&gt;').get(0).nodeName;

 equals(element1, element2, "We expect these to match");
});
</code></pre>

<p>The code above runs fine everywhere – IE, FireFox, Opera, Chrome, etc. etc. Good.</p>

<pre><code class="prettyprint lang-js">
test("Compare elements with namespace", function() {
 var element1, element2;

 element1 = document.createElement('a:spud').nodeName;
 element2 = $('&lt;a:spud/&gt;').get(0).nodeName;

 equals(element1, element2, "We expect these to match");
});
</code></pre>

<p>This runs fine in non-IE browsers, they all report the nodeName as <code>'a:spud'</code>. IE now reports the nodeName as <code>'spud'</code>. Ah. I dug through the jQuery source, tracking down the bare roots of the constructor and eventually figured out that just looking at the element itself isn't going to provide any clues. The bit that does the actual string-to-elements work (somewhere around <a href="https://github.com/jquery/jquery/blob/master/src/manipulation.js#L587">line 5619 in jQuery 1.5.2</a>) creates a container div then injects the (slightly modified) code as innerHTML. The issue must be in IE's interpretation of innerHTML, I thought to myself. And then to you by writing it here.</p>

<h2>.innerHTML aside</h2>
<h3>or ‘jQuery is clever’</h3>
<p>Before we continue with this long and, ultimately, unnecessary investigation into namespaces, I have to take a small diversion to cover some smart stuff jQuery does. One thing in particular, in fact. Around that line I mentioned earlier (5619-ish), an extra bit of text is inserted into the innerHTML to cope with IE's oddity. If you are trying to create a non-standard element using innerHTML, IE will not complain but also just do pretty much nothing at all:</p>
<pre><code class="prettyprint lang-js">        var div = document.createElement('div');
        div.innerHTML = '&lt;spud&gt;&lt;/spud&gt;';
        alert(div.innerHTML);
</code></pre>
<p>The above code will alert <code>'&lt;spud&gt;&lt;/spud&gt;'</code> in most browsers but <code>''</code> in IE. What jQuery does is firstly wrap your element in an extra <code>&lt;div&gt;&lt;/div&gt;</code> (producing <code>'&lt;DIV&gt;&lt;/DIV&gt;'</code>) then prepends the word 'div' to that. The innerHTML reported by IE is now <code>'div&lt;DIV&gt;&lt;SPUD>&lt;/SPUD&gt;&lt;/DIV&gt;'</code>! There it is! Next, the extra gubbins is removed by calling .lastChild and you're left with <code>innerHTML = '&lt;SPUD&gt;&lt;/SPUD&gt;'</code>. That's pretty darned clever.</p>

<h2>.innerHTML vs document.appendChild</h2>
<p><a href="http://jsfiddle.net/thingsinjars/4ZsKU/">View this on jsFiddle.net</a></p>
<p>Back on track. Armed with this little trick, we can reliably test innerHTML in IE using non-standard elements.</p>

<pre><code class="prettyprint lang-js">
module("Known elements (span)");
 test("Compare elements without namespace", function() {
  var div1, div2;

  div1 = document.createElement('div');
  div1.innerHTML = '&lt;span&gt;&lt;/span&gt;';

  div2 = document.createElement('div');
  div2.appendChild(document.createElement('span'));

  equals(div1.innerHTML.toLowerCase(), div2.innerHTML.toLowerCase(),
     "We expect these to match");
 });

 test("Compare elements with namespace", function() {
  var div1, div2;

  div1 = document.createElement('div');
  div1.innerHTML = '&lt;u:span&gt;&lt;/u:span&gt;';

  div2 = document.createElement('div');
  div2.appendChild(document.createElement('u:span'));

  equals(div1.innerHTML.toLowerCase(), div2.innerHTML.toLowerCase(),
     "We expect these to match");
 });
</code></pre>

<p>The first test in this pair runs fine everywhere exactly as we'd hope and expect. The second fails miserably in IE. Let us quickly run the same test with unknown elements just to make sure we're identifying the right problem:</p>

<pre><code class="prettyprint lang-js">module("Unknown elements (spud)");
 test("Compare elements without namespace", function() {
  var div1, div2;

  div1 = document.createElement('div');
  div1.innerHTML = 'div&lt;div&gt;' + '&lt;spud&gt;&lt;/spud&gt;' + '&lt;/div&gt;';
  div1 = div1.lastChild;

  div2 = document.createElement('div');
  div2.appendChild(document.createElement('spud'));

  equals(div1.innerHTML.toLowerCase(), div2.innerHTML.toLowerCase(),
     "We expect these to match");
 });
 test("Compare elements with namespace", function() {
  var div1, div2;

  div1 = document.createElement('div');
  div1.innerHTML = 'div&lt;div&gt;' + '&lt;u:spud&gt;&lt;/u:spud&gt;' + '&lt;/div&gt;';
  div1 = div1.lastChild;

  div2 = document.createElement('div');
  div2.appendChild(document.createElement('u:spud'));

  equals(div1.innerHTML.toLowerCase(), div2.innerHTML.toLowerCase(),
     "We expect these to match");
 });
</code></pre>

<p>As before, the first test in this pair works fine, the second fails. Cool. Or not. Either way, you can now see that it doesn't really matter whether the elements are standard or custom and that little diversion we took earlier really was unnecessary. Still, you know more now about some of the cleverness in jQuery than you did before.</p>

<p>It turns out the reason IE reports the nodeNames as the non-namespaced ones is because it has been busy behind the scenes and added an extra XML namespace prefix into our current context. The innerHTML of the div we filled up using innerHTML has been modified to:</p>

<pre><code class="prettyprint lang-js">  &lt;?xml:namespace prefix = u /&gt;
  &lt;u:span&gt;&lt;/u:span&gt;
</code></pre>

<p>Where'd that namespace declaration come from?! Goshdarnit, IE. From its point of view, within that little context, <code>u:span</code> is equivalent to <code>span</code></p>

<h2>The most stripped-down example</h2>
<p><a href="http://jsfiddle.net/thingsinjars/pfQbG/" title="Checking validity of innerHTML">View this on jsFiddle</a></p>
<p>Seriously, it does not get more fundamental than this.</p>
<pre><code class="prettyprint lang-js">element = document.createElement('div');
testHTML = '&lt;div&gt;&lt;/div&gt;';
element.innerHTML = testHTML;
element.innerHTML.toLowerCase() == testHTML.toLowerCase() 
</code></pre>
<p>The last line there is true for all browsers.</p>
<pre><code class="prettyprint lang-js">element = document.createElement('div');
testHTML = '&lt;a:div&gt;&lt;/a:div&gt;';
element.innerHTML = testHTML;
element.innerHTML.toLowerCase() == testHTML.toLowerCase() 
</code></pre>
<p>The last line there is true for all browsers <em>except IE 6, 7 and 8!</em></p>

<h2>In conclusion?</h2>
<p>Ultimately, there are no winners here. Identifying the problem is quite different from fixing it. I've added a note to the relevant <a href="http://bugs.jquery.com/ticket/4208">jQuery bug</a> in the tracker but it's not so much a bug in jQuery as a humorous IE quirk. There's some talk of refactoring the <a href="http://api.jquery.com/find/" title=".find() &#8211; jQuery API">.find() method</a> to handle more complicated tagnames so this might get picked up then. The fix will probably be something along the lines of checking the outcome of the innerHTML doesn't have an unexpected namespace declaration when the selector has a colon in it:</p>
<pre><code class="prettyprint lang-js">div.replace( /]*>/g, '' )</code></pre>
<p>I'd submit the patch myself but I'm having difficulty getting unmodified jQuery to build on any of my machines without failing most of the QUnit tests. I've probably typed something wrong.</p>      </div>
]]></description>
<pubDate>Fri, 01 Apr 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Autogenerated Everything</title>
<link>http://thingsinjars.com/post/369/autogenerated-everything/</link>
<guid>http://thingsinjars.com/post/369/autogenerated-everything/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-369">
        <p><a href="http://thingsinjars.com/post/369/autogenerated-everything/">Autogenerated Everything</a></p>
<p>After seeing this <a href="http://www.dubberly.com/concept-maps/3x4grid.html">collection</a> of the 892 different ways you can partition a 3 x 4 grid<a href="http://thingsinjars.com/post/369/autogenerated-everything/#generate_foot_1" id="generate_foot_a" class="footnote">1</a>, I was struck by a thought. If these were generated as HTML templates, they could be combined with a couple of other useful websites and become a nice, API-driven site builder<a href="http://thingsinjars.com/post/369/autogenerated-everything/#generate_foot_2" id="generate_foot_b" class="footnote">2</a>.</p>

<h2>The process</h2>
<ul>
	<li>On the site-building webpage, you'd enter a few keywords describing the site you want and drag a slider along between 1 and 12 to specify how many content areas you want. The value from the slider would be used to pick a template randomly from the number available for that combination of panels.</li>
	<li>This template would be dropped into the middle of an <a href="http://www.html5boilerplate.com/">HTML 5 boilerplate</a> (possibly generated via <a href="http://initializr.com">Initializr</a>)</li>
	<li>The keywords would be passed to <a href="http://colorapi.com/">ColorAPI</a> to generate an asthetically pleasing colour-scheme</li>
	<li>The keywords would then be passed to <a href="http://flickholdr.com/">FlickHoldr</a> along with the dimensions of some of the areas from the template to get relevant imagery</li>
	<li>Grab some lorem ipsum of the right length from <a href="http://loremipscream.com/api">LoremIpscream</a> to fill out the content areas of the site</li>
	<li>Done. Your asthetically pleasing, nicely designed site is ready to download within a few seconds.</li>
</ul>

<p>Once this service has been created, I'm fairly sure me and the rest of the industry will be out of a job.</p>


	<p><a id="generate_foot_1" href="http://thingsinjars.com/post/369/autogenerated-everything/#generate_foot_a" class="footnote">1</a> Technically, there are 3,164 ways you can partition the grid but most of them are vertical or horizontal mirrors of the 892 mentioned.</p>
	<p><a id="generate_foot_2" href="http://thingsinjars.com/post/369/autogenerated-everything/#generate_foot_b" class="footnote">2</a> There are a few references to <a href="http://3x4grid.com">3x4grid.com</a> which is apparently going to be an API-accessible collection of these layouts but there doesn't seem to be anything there yet.</p>
      </div>
]]></description>
<pubDate>Fri, 01 Apr 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>8 bit alpha</title>
<link>http://thingsinjars.com/post/368/8-bit-alpha/</link>
<guid>http://thingsinjars.com/post/368/8-bit-alpha/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-368">
        <p><a href="http://thingsinjars.com/post/368/8-bit-alpha/">8 bit alpha</a></p>
Another week, another launch. I really need to find a cure for whatever illness I have that results in compulsion to built stuff. Maybe there's a Builders Anonymous group where you can go for support in coming to terms with the fact that you don't always <em>have to</em> solve the problem yourself. Learn to accept that sometimes things are just the way they are.

Pshaw!

A few days ago, I read <a href="http://calendar.perfplanet.com/2010/png-that-works/">this article</a> by <a href="http://pornel.net/">Kornel Lesiński</a>. It describes the curious and interesting ways of PNGs, particularly highlighting the fact that the 8-bit PNG with an embedded alpha channel needs a lot more love than it gets. It gives you the small file sizes you get from 8-bit PNGs (resulting from the maximum 255 colour palette) but also the benefits of a full partial transparency alpha channel unlike GIFs or standard 8-bit PNGs in which pixels are on or off, nothing in between. The reason this file type is ignored is because the most common web graphic creation application in the world (Adobe Photoshop) doesn't support them. At least not yet. You need Adobe Fireworks or some other application to convert your 24-bit alpha channel images.

After a quick search turned up nothing but instructions on how to enable command-line convertion on a Linux server, I figured this would be a handy web service. Drag, Drop, Download, Done. This also gave me an excuse to play with some <a href="https://developer.mozilla.org/en/using_files_from_web_applications">File API</a> stuff. In the end, I decided to use a <a href="https://github.com/pangratz/dnd-file-upload">jQuery plugin</a> because there was a greater chance that it had been tested and bugfixed than my own script.

<h2><a href="http://www.8bitalpha.com">8-bit alpha</a></h2>

With a name like that, I had to go for a retro theme. I even created a nice <a href="http://www.8bitalpha.com/images/spinner.gif" title="eight bit indicator image">8-bit spinner</a>.

If you have a use for the service, <a href="http://twitter.com/thingsinjars">let me know</a>, if you want to learn how it works, <a href="https://github.com/thingsinjars/8bitalpha">browse the source</a>. If you want to popularise the phrase “Drag, Drop, Download, Done” for this kind of simple web application, do that too.      </div>
]]></description>
<pubDate>Fri, 25 Mar 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Shelvist</title>
<link>http://thingsinjars.com/post/367/shelvist/</link>
<guid>http://thingsinjars.com/post/367/shelvist/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-367">
        <p><a href="http://thingsinjars.com/post/367/shelvist/">Shelvist</a></p>
<p>I've been a bit quiet for the last couple of weeks. Now I can reveal why!</p>
<p>All my spare time has been taken up building <a href="http://shelvi.st/">Shelvist</a> (well, that <em>and</em> looking after a 4-month old). It's a way of keeping track of which books you have read, which ones you are currently reading and which ones you want to read. That's it. </p>
<p>Just over a year ago, I started listening to a lot of audiobooks and, 12 months after I subscribed to <a href="http://www.audible.co.uk">Audible</a>, I decided I wanted to see just how many books I'd read<a class="footnote" href="http://thingsinjars.com/post/367/shelvist/#foot_367_1">*</a>. All the existing book tracking sites (e.g. <a href="http://shelfari.com">Shelfari</a>, <a href="http://www.goodreads.com/">Goodreads</a>) focus on recommending, rating, reviewing which just seemed like hard work.</p>
<p><a id="foot_367_1" class="footnote">*</a>Listening to an audio book counts as reading. It just sounds weird if you tell people you listened to a book.</p>
<p>Building this was also a chance to learn some new tech. I've been wanting to play with <a href="http://www.cakephp.org">CakePHP</a> for a while so this seemed like the best opportunity. It's been a while since I used any kind of framework and I've never used a PHP MVC framework (although I did build one last year as an intellectual exercise).</p>
<p>I got over 90% of the site built in spare time over about 5 days and most of that was spent just reading the CakePHP docs. The reason for the lengthy delay between initial build and launch is down to that last 10%. As often happens with frameworks, <em>nearly everything</em> you'd ever need to do is bundled into some nice, easy to access functionality. That is, after all, kinda the point of a framework. It's the stuff that makes your product or website unique that proves trickier. I won't go into any details just now although I might come back to it in a later post. </p>
<p>More later, first of all, go shelve some books: <a href="http://shelvi.st/">Shelvist</a>.</p>      </div>
]]></description>
<pubDate>Fri, 18 Mar 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Scoped Style</title>
<link>http://thingsinjars.com/post/360/scoped-style/</link>
<guid>http://thingsinjars.com/post/360/scoped-style/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-360">
        <p><a href="http://thingsinjars.com/post/360/scoped-style/">Scoped Style</a></p>
I couldn't let it lie. The nifty JavaScript from <a href="http://thingsinjars.com/post/359/css-scoped/">the previous post</a> was all well and good but I had to have a go at jQuery plugin-ifying it. It has been Enpluginated.

Your options now are simple:
<ol>
<li>Have a look at <a href="http://thelab.thingsinjars.com/scoped/index.html">a demo</a></li>
<li><a href="https://github.com/thingsinjars/jQuery-Scoped-CSS-plugin">Check out the source on GitHub</a></li>
<li><a href="https://github.com/thingsinjars/jQuery-Scoped-CSS-plugin/archives/master">Download it</a> and start scoping some styles.</li>
</ol>

If you still have no idea what I'm talking about, you can <a href="http://www.w3.org/TR/html5/semantics.html#the-style-element">read about the attribute</a>. There are still a couple of bugs when the scoped blocks are deeply nested within other scoped areas so I'm hoping someone with a keen sense of how to straighten out Webkit oddness can help. When browsers don't implement functionality, it's a bit tricky to guess what they'd mean.

Aside from that, it's cross-browser (IE7+) compatible and ready to use. I'm interested to know if anyone finds it useful or finds any odd combinations of styles that don't scope nicely.      </div>
]]></description>
<pubDate>Sun, 30 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>CSS Scoped</title>
<link>http://thingsinjars.com/post/359/css-scoped/</link>
<guid>http://thingsinjars.com/post/359/css-scoped/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-359">
        <p><a href="http://thingsinjars.com/post/359/css-scoped/">CSS Scoped</a></p>
<p>Update: <a href="http://thingsinjars.com/post/360/scoped-style/">Bam! Plugin'd</a></p>
<p>One of the things in HTML5 that caught my eye a while back was the new 'scoped' attribute for style tags. The idea of it is that you can include a style element mid-document, mark it as scoped and its declarations will only apply to the style elements parent element and its child elements. The styles won't affect anything outside this. The biggest problem with bringing in this attribute is that it's not backwards compatible. If you include a style block mid-page, its declarations will be applied to ever element whose selector matches, inside or outside scope. It is anti-progressively enhancable. This means that designers and developers can't start using it until there's enough support. What we need is another of those JS tricks to make it usable.</p>

<p>Possibly the idea of having a style block dropped into the middle of a semantic document strikes you as a distasteful but thinking practically, this could make CMS workflows a bit easier and keep global stylesheets clean of lots of one-off specific styles. For example, <a href="http://thingsinjars.com/post/334/testing-css3-stuff/">this post</a> describing striped CSS backgrounds could have benefited from having the demo directly within the body of the post but, without going into the backend to add an extra id, this could have messed up the layouts for all other posts.</p>

<p>My first attempt at solving this problem with JS involved generating a unique class, adding it to the parent element and then parsing the style blocks using <a href="http://www.glazman.org/JSCSSP/">JSCSSP</a> so that I could rewrite them with the new class to add specificity. This approach only worked for the most basic declarations, unfortunately. The parser worked perfectly but there's a lot of detail in CSS specificity that mean this would be a much larger problem than I thought.</p>

<p>My second attempt involved:</p>
<ol>
<li>Allowing the style blocks to affect everything on the page (at which point, the elements in-scope look right, those out-of-scope look wrong)</li>
<li>Using JS to read the current computed styles of each element in-scope and copy them to a temporary array</li>
<li>Emptying out the scoped style element (in-scope look wrong, out-of-scope looks right)</li>
<li>Copying the styles back from the temporary array onto each element</li>
</ol>

<p>The first couple of versions only work in webkit, the latest (below) works in mozilla, too.</p>

<p>This <a href="http://thelab.thingsinjars.com/scoped/index-single.html">worked great</a> unless you had <a href="http://thelab.thingsinjars.com/scoped/index-multiple.html">more than one</a> scoped block – step 1 allowed scoped styles to affect each other.</p>

<p>The current attempt involves temporarily emptying all other scoped styles before taking the computed styles from a block. I'm now just thinking that this method might not work if you have multiple scoped blocks within the same context. Oh well, there's something to fix in the future.</p>

<p><a href="http://thelab.thingsinjars.com/scoped/index-js.html">This is where I'm at just now</a>.</p>

<p>Yes, it's a mess, yes the JS is scrappy and yes, it doesn't currently work in IE but I'll get round to that next. It took long enough to get it working in Firefox as there's no simple way to convert a ComputedCSSStyleDeclaration to a string in Mozilla unlike Webkit's implementation of cssText or IE's currentStyle. I might even make it into one of those new-fangled jQuery plugins everyone's using these days.</p>
      </div>
]]></description>
<pubDate>Fri, 28 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>jQTouch Calendar Extension</title>
<link>http://thingsinjars.com/post/357/jqtouch-calendar-extension/</link>
<guid>http://thingsinjars.com/post/357/jqtouch-calendar-extension/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-357">
        <p><a href="http://thingsinjars.com/post/357/jqtouch-calendar-extension/">jQTouch Calendar Extension</a></p>
I needed to build an offline calendar in jQTouch for a project and found this particularly nice-looking <a href="http://code.google.com/p/jqtouch-ical/">jQTouch iCal project</a> by <a href="http://www.balexandre.com/">Bruno Alexandre</a>. Unfortunately, it required a server connection.

A day later and I've pulled the thing apart, refactored and rebuilt into a shiny jQTouch extension (still using the original project's CSS). It's built for Mobile Safari but still looks good in other webkits.

<a href="http://thelab.thingsinjars.com/jqt.calendar/">View a demo</a>

Grab the code from <a href="https://github.com/thingsinjars/jQTouch-Calendar">the GitHub repository</a>
      </div>
]]></description>
<pubDate>Wed, 26 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Uncooked Composition 5</title>
<link>http://thingsinjars.com/post/356/uncooked-composition-5/</link>
<guid>http://thingsinjars.com/post/356/uncooked-composition-5/</guid>
<description><![CDATA[
        <div class="teaser audio" id="teaser-356">
        <p><a href="http://thingsinjars.com/post/356/uncooked-composition-5/">Uncooked Composition 5</a></p>
Now for a complete break from the norm... a guitar.

I'm not nearly as confident improvising on the guitar as I am on the piano. Mostly because discordant noises on the piano sound intentional. The same noise on a guitar sounds like failure.

Still, I found this in amongst a pile of old recordings (a virtual pile, it was on a backup drive). It was recorded some time in late 2003, I think. As always, there's a bit of a stutter at the start. That's kind of the point of <a href="http://thingsinjars.com/post/336/uncooked-composition/">this project</a>.      </div>
]]></description>
<pubDate>Mon, 11 Apr 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Uncooked Composition 4</title>
<link>http://thingsinjars.com/post/355/uncooked-composition-4/</link>
<guid>http://thingsinjars.com/post/355/uncooked-composition-4/</guid>
<description><![CDATA[
        <div class="teaser audio" id="teaser-355">
        <p><a href="http://thingsinjars.com/post/355/uncooked-composition-4/">Uncooked Composition 4</a></p>
Listening again to these tracks makes me think I must have spent a lot of my time in the 80s watching heartwarming, uplifting, made-for-tv movies.

This should be thought of as a companion piece to the <a href="http://thingsinjars.com/post/354/uncooked-composition-3/">waltzy</a> one from before as there was 23 seconds between finishing that one and starting to record this one.

As described <a href="http://thingsinjars.com/post/336/uncooked-composition/">here</a>, this is one of a series of random, unprocessed piano doodles posted to remind me to play more often.      </div>
]]></description>
<pubDate>Mon, 28 Mar 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Uncooked Composition 3</title>
<link>http://thingsinjars.com/post/354/uncooked-composition-3/</link>
<guid>http://thingsinjars.com/post/354/uncooked-composition-3/</guid>
<description><![CDATA[
        <div class="teaser audio" id="teaser-354">
        <p><a href="http://thingsinjars.com/post/354/uncooked-composition-3/">Uncooked Composition 3</a></p>
I apparently felt in a waltzy mood when I recorded this one      </div>
]]></description>
<pubDate>Tue, 25 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Toolkit</title>
<link>http://thingsinjars.com/post/351/toolkit/</link>
<guid>http://thingsinjars.com/post/351/toolkit/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-351">
        <p><a href="http://thingsinjars.com/post/351/toolkit/">Toolkit</a></p>
I'm not entirely sure what the toolkit's for but it's got everything she needs.

Again, the <a href="http://bashcorpo.deviantart.com/art/Grungy-paper-texture-v-5-22966998">paper texture</a> came from here. This was basically an excuse to look at pictures of Diana Rigg...      </div>
]]></description>
<pubDate>Thu, 20 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>I wish...</title>
<link>http://thingsinjars.com/post/350/i-wish/</link>
<guid>http://thingsinjars.com/post/350/i-wish/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-350">
        <p><a href="http://thingsinjars.com/post/350/i-wish/">I wish...</a></p>
What do you do when you find a nice <a href="http://bashcorpo.deviantart.com/art/Grungy-paper-texture-v-5-22966998">paper texture</a>? Juxtapose a couple of pop culture references on it and Save for Web.

That's what I do, anyway.      </div>
]]></description>
<pubDate>Tue, 18 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>iMagritte</title>
<link>http://thingsinjars.com/post/349/imagritte/</link>
<guid>http://thingsinjars.com/post/349/imagritte/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-349">
        <p><a href="http://thingsinjars.com/post/349/imagritte/">iMagritte</a></p>
Some silly fun.

Here's my take on the Magritte painting <a href="http://en.wikipedia.org/wiki/The_Son_of_Man_(Magritte)">The Son of Man</a>.      </div>
]]></description>
<pubDate>Thu, 13 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Context-free content and content-agnostic design</title>
<link>http://thingsinjars.com/post/348/context-free-content-and-content-agnostic-design/</link>
<guid>http://thingsinjars.com/post/348/context-free-content-and-content-agnostic-design/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-348">
        <p><a href="http://thingsinjars.com/post/348/context-free-content-and-content-agnostic-design/">Context-free content and content-agnostic design</a></p>
<p>Last year I wrote about the trend towards separation between the design creators and the content creators and I think it&rsquo;s time to revisit that topic. The idea was that, although the tools of the future would mean there would be less need for individual content to be designed and developed by hand, there would be an increasing number of opportunities for content to be viewed within the context the consumer wants to view it rather than the way the designer wanted it viewed.</p>
<p>Okay, that sounds a lot more complicated than it is. Here&rsquo;s a scenario:</p>
<h2>Part One</h2>
<ol>
   <li>I write interesting articles</li>
   <li>I post them on my MySpace-inspired, geocities refugee, blink-tag-heavy page</li>
   <li>You refuse to read them because the design literally makes your eyeballs itchy.</li>
</ol>
<h2>Part Two</h2>
<ol>
   <li>Some other guy writes reeeeeeeally dull articles</li>
   <li>He posts them on his beautifully-designed, subtly gradiented, drop-shadowed, Helvetica Neue Light site</li>
   <li>You refuse to read them because the content is so dull your heart-rate slows almost to a stop and you forget to breathe.</li>
</ol>
<p>The type of content/design separation I&rsquo;m talking about here would mean you take my wonderfully written articles, his exquisitely-designed layout and put the two together. Technically, you might be able to create a brain-numbingly-dull but eye-ball-searing monster out of the left-over parts but you shouldn&rsquo;t. At the moment, we can&rsquo;t just take any arbitrary design and apply it to any arbitrary content but it won&rsquo;t be that long. As I mentioned last year, the separation of design and content is not a bad thing for designers, in fact, it&rsquo;s an opportunity to create a better content consumption experience than the next guy.</p>
<p>The last year has provided a great number of examples of this trend and it seems it can only continue. Some of the more high-profile ones are:</p>
<h2><a href="http://www.flipboard.com/">FlipBoard</a></h2>
<p>The hype around this was so immense that <em>everybody</em> absolutely <em>had to have it</em> on launch day. It was so popular, in fact, that it was about a week before anyone could actually use it, the load on their servers bringing them grinding to a halt. It was kinda justified, though. Having all of your own tailored content pulled from Twitter, FaceBook and any number of recommended channels (groups of RSS feeds and websites) then presented to you as a personalised magazine is quite enjoyable. The creators got into a bit of trouble for screen-scraping (what they refer to as &lsquo;<a href="http://gizmodo.com/5594176/is-flipboard-legal">parsing</a>&rsquo;) rather than using the content the way the creators intended but that seemed to die down once the content creators realised they were still getting the ad revenue.</p>
<h2><a href="http://reederapp.com/">Reeder</a></h2>
<p>This really applies to any RSS reader but Reeder by Silvio Rizzi is a particularly nice and well-known example. RSS is really the best example of context-free content where, for many years now, the audience has had the ability to take in the content of articles in their reader of choice. Initially, this was for convenience &ndash; why access content in 20 different places when you could access one &ndash; but now that the RSS-consuming public are au fait with that, it has moved on to more aesthetic concerns. Reeder presents articles in off-black text on an off-white background in Helvetica. It&rsquo;s possibly an overused visual clich&eacute; but it&rsquo;s a nice one and it works.</p>
<h2>Bookmarklets, UserScript, UserStyles and Extensions</h2>
<p>There are a number of bookmarklets whose specific purpose is to apply a predefined design to any arbitrary content. Many of them use Helvetica. Although Bookmarklets have been around for a long time, their popularity never really took off with the mainstream web audience. It&rsquo;s probably something to do with the conflicting messages tech-types give to non-tech-types: &ldquo;Never install programs from the web, they&rsquo;re almost certainly viruses&rdquo; and &ldquo;A Bookmarklet is a little program that runs in your browser...&rdquo;. UserScripts keep pushing the boundaries for what is possible via JS but require a level of technical ability beyond the vast majority. UserStyles are a more passive way of doing many of the same things as UserScripts and Bookmarklets although whereas they run JS and actively modify the page, UserStyles take the markup they&rsquo;re given and change it.</p>
<p>At the moment, it seems the most user-understandable way to enhance the browser experience is with browser extensions, even if they are simply used to run the same JS you&rsquo;d have in a bookmarklet or a userscript.</p>
<h2><a href="http://helvetireader.com/">Helvetireader</a></h2>
<p>We&rsquo;re getting quite meta here. If you&rsquo;re using Google Reader for consuming your RSS, you&rsquo;ve already brought the content into a new context. Helvetireader from <a href="http://www.hicksdesign.co.uk">Jon Hicks</a> takes that content and overlays another design. Which uses Helvetica.</p>
<h2><a href="http://lab.arc90.com/experiments/readability/">Readability</a></h2>
<p>I mentioned this briefly last year. This is probably the highest-profile bookmarklet in this field. In the words of the creators, <a href="http://www.arc90.com/">arc90</a>, it &lsquo;...makes reading on the Web more enjoyable by removing the clutter...&rsquo; actually, that&rsquo;s a far better way of describing what I&rsquo;m talking about than my whole first three paragraphs. This allows a few variations in designs giving the user a bit more control over how they want things presented.</p>
<h2><a href="http://www.notforest.com/">NotForest</a></h2>
<p>This is superficially similar to readability but whereas with readability, you customise the design before you install the bookmarklet, this allows you to choose your design each time it is launched.</p>
<h2>More than words...</h2>
<p>When I&rsquo;m referring to content, I don&rsquo;t just mean text. Any media &ndash; audio, video, photo &ndash; can be separated from its original context and presented in a more accessible way. <a href="http://quietube.com">QuietTube</a> does this for YouTube videos, presenting them on a white page with no recommended videos, no channel subscription buttons and, most importantly, no comments<a href="http://thingsinjars.com/post/348/context-free-content-and-content-agnostic-design/#footnote348-2" class="footnote" id="footnote348-b">[1]</a>. <a href="http://flickriver.com">Flickriver</a> presents the photos from a Flickr user&rsquo;s account on a black background in an endless scroll so that you can just immerse yourself in the photos without having to look for the &lsquo;next&rsquo; button every time. <a href="http://huffduffer.com">Huffduffer</a> picks up any audio files you want in webpages and gives them to you as an RSS feed that can be subscribed to in iTunes. You&rsquo;re taking the audio out of its original context and consuming it how you choose.</p>
<p><a id="footnote348-2" class="footnote">[1]</a>YouTube comments are a great way to remind yourself that IQ 100 is an <em>average</em>. Half of the population are below that.<a href="http://thingsinjars.com/post/348/context-free-content-and-content-agnostic-design/#footnote348-b" class="footnote">&uarr;</a></p>      </div>
]]></description>
<pubDate>Thu, 13 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Yet another wood texture</title>
<link>http://thingsinjars.com/post/346/yet-another-wood-texture/</link>
<guid>http://thingsinjars.com/post/346/yet-another-wood-texture/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-346">
        <p><a href="http://thingsinjars.com/post/346/yet-another-wood-texture/">Yet another wood texture</a></p>
The web needs more wood textures. If there's one thing the web is short of, it's wood textures.

Here's a wood texture I photographed, tidied and straightened. 

Enjoy.

<a href="http://thingsinjars.com/uploaded/images/expanded/wooden-panel.jpg">Wooden Panels [JPG - 6MB]</a>      </div>
]]></description>
<pubDate>Wed, 04 May 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Cash machine frustrations</title>
<link>http://thingsinjars.com/post/344/cash-machine-frustrations/</link>
<guid>http://thingsinjars.com/post/344/cash-machine-frustrations/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-344">
        <p><a href="http://thingsinjars.com/post/344/cash-machine-frustrations/">Cash machine frustrations</a></p>
<p>Cash machines, ATMs, AutoTellers, Cashpoints... whatever you call them in your bit of the world, have been around <a href="http://www.bbc.co.uk/london/content/articles/2007/06/26/cash_machine_feature.shtml">since the 1960s</a> and yet there is still no user-interface standardisation. There’s a wide difference in user experiences, designs, hardware, layout. A certain amount can be attributed to the kind of variation you’d expect – font, colour, terminology – but after almost 50 years, there’s still a gulf between a good experience – the kind where you barely notice the machine: you have a task, you do it, you’re done – and a bad one – the kind that would prompt you to write a post about it, for example.</p>

<p>It may seem like a trivial thing to most people but I find I’ve actually started avoiding the machine near my house just because it is the worst offender I have ever come across in terms of consistency, design and sense. This interface was definitely planned by programmers and not designers.</p>

<p>Roughly, the process goes like this:</p>

<h2>Screen one</h2>
<pre class="uncode">

Insert your card

</pre>

<p><em>Inserts card</em></p>

<p>Okay so far.</p>

<h2>Screen two</h2>
<pre class="uncode">

Please type your PIN then press Enter

</pre>
<p><em>beep, beep, beep, beep<a href="http://thingsinjars.com/post/344/cash-machine-frustrations/#footnote344-1" class="footnote" id="footnote344-a">[1]</a>, look for the Enter button...</em></p>


<h2>Screen three</h2>
<pre class="uncode">

Please wait, processing...

</pre>
<p><em>Wait, I haven’t pressed enter yet! Apparently I didn’t need to press enter, did I? You were lying when you said ’press Enter’. You’re already making me dislike you.</em></p>

<h2>Screen four</h2>
<pre class="uncode">

Would you like a receipt with this transaction?






                         yes >
                          no >

</pre>

<p>The gap between the question (at the top of the screen) and the options (at the bottom) is just big enough to make me want to double-check the question. This would be much better if the options were themselves descriptive:</p>
<pre class="uncode">

       I want a receipt >
I do not want a receipt >

</pre>

<p>Even better if this was asked at the end of the transaction. Maybe I haven’t decided whether or not I want a receipt. I’ll have a better idea <em>after</em> my transaction. What if I say no now and change my mind later? Is it too late then? Will I get another chance? Oh no, I’m hyper-ventilating...</p>

<p>Related to this screen is my biggest cause for complaint. When there is no receipt paper left what does the machine do? Miss out this question? Replace it with a single notification screen? No, instead, we get this screen:</p>

<h2>Screen four, take 2</h2>
<pre class="uncode">

Unable to print receipt, would you like to continue
with this transaction?






                         yes >
                          no >

</pre>

<p>If you’re in the habit of anticipating the receipt question, you’re prepped and ready to press ’no’ as in "No, I don’t want a receipt". However, if this screen comes up, even if you notice the question is different, nine times out of ten, muscle memory kicks in and you find yourself pressing it anyway with a voice in your head shouting ’Stooooop!’ at whatever’s controlling your finger. You press it, your card is spat out, you have to start again. This experience will ensure that the next time you’re presented with the screen, you’ll double-check the question then the options then the question and then the options. Twice. Even if you try to scan the text, your eyes will still pick out ’receipt’ in the middle and ’with this transaction’ at the end. That doesn’t help, you actually need to read and comprehend fully. And here was you thinking you only wanted to get some cash out.</p>

<h2>Screen five</h2>
<pre class="uncode">

Please select transaction






                         View Balance >
                             Withdraw >

</pre>

<p>I don’t have too many complains about this screen except for the unnecessary distance between the question and the options. It is a touch irksome that they’ve now switched to action-based label text ("view") from the option-based labels ("yes" above)</p>

<h2>Screen six</h2>
<pre class="uncode">

Please select amount to withdraw


        < £100                  Other >
        < £70	                   £50 >
        < £40	                   £30 >
        < £20	                   £10 >

</pre>

<p><em>I would like £30, please. *beep*</em></p>

<h2>Screen seven</h2>
<pre class="uncode">

Please wait, processing...

</pre>

<p>About 30% of the time, this is the next screen:</p>

<h2>Screen eight</h2>
<pre class="uncode">

Unable to dispense required amount. Please enter a
different amount.

   Suggested amount(s): £20, £40

   £[   ]

</pre>
<p>There are several annoyances with this screen:</p>
<ol>
	<li>why was I even asked if I wanted £30 if the machine was never going to give me £30? </li>
	<li>what if I were to type in £50? Would the machine also be unable to dispense that amount? £20 and £40 are suggestions but there’s nothing to say why I can’t have £50.</li>
	<li>was it so utterly impossible for the programmers to figure out whether they were displaying one suggested amount or two? There should never be any reason for dynamically generated text to resort to the bracket(s).</li>
</ol>

<p>As an aside, this reminds me of an online mortgage calculator I used once where you’d enter an amount like ”£20,000“ and it would say ”Incorrect Value“ but not say what was wrong so you’d try ”20,000“, ”Incorrect Value“, ”20000“, ”Incorrect Value“, ”£20000“, ”Thank you“.</p>

<p>The operators of these machines must have a lot of usage statistics so rather than give equal billing to all possible options throughout the process, why not reorganise so that the greatest number of people have the smallest amount of work to do? If 90% of users use the machines to withdraw £20, put that on the front screen (just after the PIN). Don’t insist on brand colours when they’re annoyingly intrusive on the user experience. Heck, why not just set the whole thing in off-black Helvetica on an off-white background with that ubiquitous swiss red colour?</p>

<p>I’d rather something like this</p>
<p><img src="http://thingsinjars.com/uploaded/images/thumbs/ATM-nice-thumb.png" alt="Nice-looking ATM"></p>
<p>than something like this</p>
<p><img src="http://thingsinjars.com/uploaded/images/thumbs/ATM-nasty-thumb.png" alt="Nasty-looking ATM">
</p>

<h2>Am I over-reacting?</h2>
<p>Yes, completely. That’s not the point. Well thought-out user interfaces are what separates us from the animals. Or something like that. There are now <a href="http://www.atmia.com/mig/globalatmclock/">over 2 million ATMs in the world</a>, so unifying them will probably never happen but that doesn’t give the designers of the next generation of machines free reign to start from scratch all over again.</p>

<h2>Am I generalising?</h2>
<p>Okay, maybe a bit. Maybe a lot, actually. I’ve successfully used ATMs in a number of countries in a variety of languages but then, I do ‘tech stuff’ for a living. Without getting my hands on those usage statistics, I couldn’t really say.</p>
<p>Anyway, aren’t we supposed to be paying for everything by thumbprint these days?</p>

<p><a id="footnote344-1" class="footnote">1</a>Note, this is not my actual PIN, that would be ‘beep, beep, beep, beep’<a href="http://thingsinjars.com/post/344/cash-machine-frustrations/#footnote344-a" class="footnote">↑</a></p>      </div>
]]></description>
<pubDate>Tue, 11 Jan 2011 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Uncooked Composition 2</title>
<link>http://thingsinjars.com/post/338/uncooked-composition-2/</link>
<guid>http://thingsinjars.com/post/338/uncooked-composition-2/</guid>
<description><![CDATA[
        <div class="teaser audio" id="teaser-338">
        <p><a href="http://thingsinjars.com/post/338/uncooked-composition-2/">Uncooked Composition 2</a></p>
Here's another short session of random piano noodling. As far as I can picture, this would be suitable for a montage in a film where the protagonist is mulling over the fact that his wife has left him and it takes him a while to get used to the idea but he finds solace in his dog. Or something like that.

If the end seems a bit abrupt, it's because Jenni came in and reminded me we were actually supposed to have gone to the shops 10 minutes previous.      </div>
]]></description>
<pubDate>Thu, 09 Dec 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Uncooked Composition</title>
<link>http://thingsinjars.com/post/336/uncooked-composition/</link>
<guid>http://thingsinjars.com/post/336/uncooked-composition/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-336">
        <p><a href="http://thingsinjars.com/post/336/uncooked-composition/">Uncooked Composition</a></p>
<p>Music, much like mathematics, is a young person's game. If you haven't made it by the time you're 25, your chances of making an impact on the world are significantly diminished. That's not to say it's impossible, it's just much less likely.</p>
<p>Basically, I'm beginning to come to the realisation I'm not going to be a rock star. I might not even make it into space. To that end, I've decided that, instead of scribbling away at writing and rewriting the same songs I've been trying to improve for the last 10 years, I'd go the other way. A few months ago, I put a dictaphone next to the piano and started recording the occasional random improvisation. Originally, the idea had been to pick the best bits and rework them for some reason or another but after listening back to them, I found there's some appeal in just hearing the raw first-take complete with do-overs and occasional accidental 'quotes' from other pieces.</p>
<p>Over the next little while, I'll be uploading some of them just so that I know I've done something with them other than leave them on a tape in the back of a drawer. When listening to them, bear in mind two things:</p>
<ol>
<li>The piano needs retuned almost every week so some of it might be a bit rough.</li>
<li>This is, as the title says, 'Uncooked Composition'. I come in from work, take my shoes off, sit down at the piano, press record. There's no post-processing anywhere so there will be mistakes and do-overs.</li>
</ol>


<a href="http://thingsinjars.com/uploaded/audio/uncooked-1.m4a">Download the file</a>
      </div>
]]></description>
<pubDate>Sun, 05 Dec 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Testing CSS3 stuff</title>
<link>http://thingsinjars.com/post/334/testing-css3-stuff/</link>
<guid>http://thingsinjars.com/post/334/testing-css3-stuff/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-334">
        <p><a href="http://thingsinjars.com/post/334/testing-css3-stuff/">Testing CSS3 stuff</a></p>
<p>You may have seen Google's 'Watch this space' advertising appearing all over the place. They have quite eye-catching diagonally striped backgrounds in various colours. A couple of days ago, I was wondering how easy it would be to recreate this in CSS without images. Unfortunately, the state of CSS 3 is such that some things work wonderfully, some just plain don't (scoped attribute, I'm looking at you). The following code relies on vendor extensions and so, unless you're willing to tend it and correct it after the spec is finalised, don't use this on a production server.</p>
<p>The most obvious thing to notice from the following code, though, is the competing syntax for the repeating linear gradient style. Mozilla have separated it into a distinct style (<code>-moz-repeating-linear-gradient</code>) while Webkit have built it as an option to their general gradient style (<code>-webkit-gradient</code>).</p>
<pre><code class="prettyprint">body {
	background-image: -moz-repeating-linear-gradient(
		-45deg,
		transparent,
		transparent       25%,
		rgba(0,0,0,0.15)  25%,
		rgba(0,0,0,0.15)  50%,
		transparent       50%,
		transparent       75%,
		rgba(0,0,0,0.15)  75%,
		rgba(0,0,0,0.15)
	);
	background-image: -webkit-gradient(
		linear,
		0% 0%,
		100% 100%,
		from(transparent),
		color-stop(0.25, transparent),
		color-stop(0.25, rgba(0,0,0,0.15)),
		color-stop(0.50, rgba(0,0,0,0.15)),
		color-stop(0.50, transparent),
		color-stop(0.75, transparent),
		color-stop(0.75, rgba(0,0,0,0.15)),
		to(rgba(0,0,0,0.15))
	);
}</code></pre>
<p>To get a better idea of what this does, view source on <a href="http://thelab.thingsinjars.com/watch-these-stripes.html">this demo page</a>. This includes a button to change the class on the body (using JS) which simply changes the background colour – the stripes are semi-transparent on top of that. Remember, due to the vendor prefixes, this only works in -moz or -webkit browsers.</p>
<p>It's supposed to look like this:</p>
<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/striped.png" rel="lightbox"><img src="http://thingsinjars.com/uploaded/images/thumbs/striped.png" /></a></li></ul>      </div>
]]></description>
<pubDate>Wed, 08 Dec 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Fake girl protects fake fish from fake cat</title>
<link>http://thingsinjars.com/post/305/fake-girl-protects-fake-fish-from-fake-cat/</link>
<guid>http://thingsinjars.com/post/305/fake-girl-protects-fake-fish-from-fake-cat/</guid>
<description><![CDATA[
        <div class="teaser flickr" id="teaser-305">
        <p><a href="http://thingsinjars.com/post/305/fake-girl-protects-fake-fish-from-fake-cat/">Fake girl protects fake fish from fake cat</a></p>
<p><a href="http://farm5.static.flickr.com/4109/5038514679_1000c33ca7.jpg"  rel="lightbox[{smod:id}]"  title="Fake girl protects fake fish from fake cat"><img src="http://farm5.static.flickr.com/4109/5038514679_1000c33ca7_m.jpg" alt="Fake girl protects fake fish from fake cat"/></a>I decided to make my desktop more dramatic...</p>
<p>Originally uploaded by <a href="http://www.flickr.com/photos/thingsinjars/5038514679/">thingsinjars</a> on <a href="http://www.flickr.com">flickr</a></p>      </div>
]]></description>
<pubDate>Mon, 25 Oct 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>The Elementals</title>
<link>http://thingsinjars.com/post/304/the-elementals/</link>
<guid>http://thingsinjars.com/post/304/the-elementals/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-304">
        <p><a href="http://thingsinjars.com/post/304/the-elementals/">The Elementals</a></p>
<p>In one of my day jobs I do something involving education, large public institutions and web stuff and a while back I thought it might be an excellent idea to have a go at designing some cool educational toys. Learnin' 'n' Fun! At the same time! omg! And so forth!</p>  

<p>The idea was to build the kind of thing you could use to squeeze knowledge into people's heads without them complaining. Y'see, it's never a good thing to <em>trick</em> people into learning. If your educational toy/game/experience relies too much on hiding the information behind the fun then the big reveal at the end – "Ha, I tricked you into learning something!" – will leave the player feeling cheated and not change their attitude towards learning. If, on the other hand, you try and push the ideas you want to get across at the expense of the core game mechanic, you'll end up with a bored user. My opinion is that you've got to be up front about the learning. You've got to say to the user "Look, this is learning and it's fun. No tricks here, it's exactly what it looks like". As for getting it to appeal in the first place, I find that very few things can beat extremely cute cartoons.</p>

<p>To that end, I present my first dabble in interactive educational whaddyamacallits: <a href="http://itunes.apple.com/app/the-elementals/id383675775?mt=8">The Elementals</a>, a fun periodic table where every element has its own unique personality.</p>
<p style="text-align:center;"><img src="http://thingsinjars.com/uploaded/images/elementals.jpg" alt="The Elementals" /></p>

<p>It's available as an iPhone app initially but I'll be venturing into the Android Marketplace soon and putting it online as a web app.</p>
<p style="text-align:center;"><a href="http://itunes.apple.com/app/the-elementals/id383675775?mt=8" style="border:0;"><img src="http://thingsinjars.com/uploaded/images/available.png" alt="Available on the App Store" /></a></p>      </div>
]]></description>
<pubDate>Fri, 15 Oct 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Appington concept</title>
<link>http://thingsinjars.com/post/303/appington-concept/</link>
<guid>http://thingsinjars.com/post/303/appington-concept/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-303">
        <p><a href="http://thingsinjars.com/post/303/appington-concept/">Appington concept</a></p>
<p>Note: this is a concept sketch only. This doesn't actually exist. It'd be cool if it did, though.</p>

<h2>Appington. Your applications brought to you.</h2>

<p><img src="http://thingsinjars.com/uploaded/images/appington/logo.png" alt="Appington Logo" style="float:right;" />Appington is, fundamentally, a single-application VNC client with a simple interface for task switching. Where most VNC applications present the user with the entire screen, Appington only shows a single window at any one time. This simplified interface makes interaction easier and saves on client application memory and reduces data transfer allowing the viewer to be more responsive. In some applications, this data transfer saving may be used to facilitate audio capture and transmission.</p>

<h2>Applications list</h2>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/appington/1-App-list.jpg" rel="lightbox[1]" title="Application List"><img src="http://thingsinjars.com/uploaded/images/appington/thumbs/1-App-list.jpg" /></a></li>
</ul>
<p>This screen shows a list of all available applications grouped by first letter. In the lower-left, the user can toggle between listing all applications or only listing currently running applications. The right-hand panel shows more information about the selected application. In this example, Google Chrome is selected and running. The current memory and CPU usage are shown along with a note of how many active windows the application has. Because Chrome is currently running, the option to quit is shown. If we had selected an unlaunched application, this button would show the option to launch. In case of emergencies, there is always the option to Force Quit a running application.</p>

<h2>Application window (portrait)</h2>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/appington/2-App-running.jpg" rel="lightbox[2]" title="Application List"><img src="http://thingsinjars.com/uploaded/images/appington/thumbs/2-App-running.jpg" /></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/appington/3-App-menu.jpg" rel="lightbox[2]" title="Application menu access"><img src="http://thingsinjars.com/uploaded/images/appington/thumbs/3-App-menu.jpg" /></a></li>
</ul>
<p>This shows a standard single application window. The button in the top left would return the user to the previous screen. From the right, the remaining buttons allow the user to capture a screen shot, maximize the application window to match the current iPad viewport (if possible), refresh the current screen (in case of render errors) and access the application's menu. In OS X, menu access would be accomplished by way of the accessibility API. At the moment, I'm not sure how it would work on other OSs.</p>

<h2>Application window (landscape)</h2>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/appington/4-App-landscape.jpg" rel="lightbox[3]" title="Application window (landscape)"><img src="http://thingsinjars.com/uploaded/images/appington/thumbs/4-App-landscape.jpg" /></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/appington/5-App-Landscape-Multiple-windows.jpg" rel="lightbox[3]" title="Application window switcher"><img src="http://thingsinjars.com/uploaded/images/appington/thumbs/5-App-Landscape-Multiple-windows.jpg" /></a></li>
</ul>
<p>This shows a single window of an application with multiple windows. You'll notice the extra button at the top between Menu and Refresh. This menu will allow you to select which window you want to access between however many the application currently has open.</p>

<h2>Other images</h2>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/appington/6a-homescreen.jpg" rel="lightbox[4]" title="Application icon on homescreen"><img src="http://thingsinjars.com/uploaded/images/appington/thumbs/6a-homescreen.jpg" /></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/appington/7-Splash.jpg" rel="lightbox[4]" title="Application launch screen"><img src="http://thingsinjars.com/uploaded/images/appington/thumbs/7-Splash.jpg" /></a></li>
</ul>
<p>The partner application to this is a modified VNC server running on the host machine. It is responsible for window management, task-switching, menu parsing and audio capture (à la <a href="http://cycling74.com/products/soundflower/" title="Soundflower – Cycling 74">SoundFlower</a>). If there is already a VNC server running, the partner app will leave the standard VNC functionality alone and act purely as a helper, providing the extra functionality but not using extra memory by duplicating functionality. This is a variation of <a href="http://kanaka.github.com/noVNC/" title="noVNC">noVNC</a> using the python proxy to manage the socket connection allowing the client to be built in <a href="http://www.phonegap.com/" title="PhoneGap">PhoneGap</a> using HTML 5.</p>
<p>Like I said at the top, this hasn't been built yet. It'd be cool if someone did build it, though.</p>      </div>
]]></description>
<pubDate>Mon, 11 Oct 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Tokyo Recommendations</title>
<link>http://thingsinjars.com/post/302/tokyo-recommendations/</link>
<guid>http://thingsinjars.com/post/302/tokyo-recommendations/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-302">
        <p><a href="http://thingsinjars.com/post/302/tokyo-recommendations/">Tokyo Recommendations</a></p>
<p>A friend recently asked me for some recommendations for what she could do on a trip to Tokyo. I pretty much always recommend the same things so I thought I'd write them up with maps and streetview and the like.</p>

<h2>Food</h2>
<p>If you're going out for food the best place I can recommend is Shin Hi no Moto (a.k.a. Andy's Izakaya). It's run by a friendly English guy (Andy) and his family. It gets really busy later on so you're best to phone and book on +81 3 3214 8021. It's okay, you can book in English. They do amazing sashimi platters and big mugs of beer. Just make sure you don't order rice (there's no rice in an izakaya and they might scowl at you if you do). You can get there by taking the Yamanote line to Yurakucho.</p>
<ul>
<li><a href="http://goo.gl/iQf9">Andy's Shin Hi no Moto</a></li>
</ul>

<p>For general daily eats, I'm addicted to Yoshinoya. Especially their Gyuu-don. Tasty, healthy and cheap. You can find Yoshinoya everywhere.</p>

<h2>Walks</h2>
<h3>West Central Tokyo</h3>
<p>If you're going to be there over a Sunday, you have to go to Harajuku. Even if you aren't there on a Sunday, the walk up Takeshita-dori is great fun. Here's a map of a little walk you can take up Takeshita-dori, round Harajuku and down to Shibuya:</p>
<ul>
<li><a href="http://goo.gl/maps/JKzU">Takeshita-Harajuku-Shibuya</a></li></ul>

<h3>North-East Central Tokyo</h3>
<p>If you fancy some culture, try this route. It takes in the Imperial Palace, Sumo museum and Edo-Toyko museum. You can finish off in Akihabara for sheer geek awesome or save that for another day.</p>
<ul>
<li><a href="http://goo.gl/maps/Svuo">Imperial Palace-Edo-Tokyo Museum</a></li></ul>

<h3>Tokyo bay/Odaiba</h3>
<p>Some people called me crazy for enjoying it but I like the walk across the rainbow bridge to Odaiba. Take the Yamanote to Tamachi and wander east-ish. You'll see the bridge once you're closer to the shore. You can take the lift up to the start of the walk and then wander out for some amazing views. It is, unfortunately, very noisy due to all the traffic but it's worth it. Head right across the bridge and follow it down, it'll probably take about an hour. Once you're on dry land again on Odaiba, you can wander around the shopping malls there (Aquacity, Seaside mall), take in the <a href="http://www.flickr.com/photos/thingsinjars/2660481457/">Statue of Liberty</a>, go for a bite to eat and eventually head back. If you time it for getting dark, you can either get some amazing views of the <a href="http://www.flickr.com/photos/thingsinjars/2128224837/">bridge lit up at night</a> or just enjoy the Yurikamome ride back (it's a completely automated train with no driver).
<ul>
<li><a href="http://goo.gl/maps/c044">Rainbow Bridge-Odaiba-Yurikamome</a></li></ul>

<h2>Views</h2>
<p>For the best view across Tokyo, the Tokyo Metropolitan Government building (a.k.a. TMG or Tocho) really can't be beaten (especially as it's free to go up). It's in Shinjuku.</p>
<ul>
<li><a href="http://goo.gl/maps/VX7i">Tokyo Metropolitan Government building</a></li></ul>      </div>
]]></description>
<pubDate>Mon, 06 Dec 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Bad tweet, go to your room</title>
<link>http://thingsinjars.com/post/301/bad-tweet-go-to-your-room/</link>
<guid>http://thingsinjars.com/post/301/bad-tweet-go-to-your-room/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-301">
        <p><a href="http://thingsinjars.com/post/301/bad-tweet-go-to-your-room/">Bad tweet, go to your room</a></p>
<p>Disclaimer: I'm not a social media guru, consultant, expert, doctor, nurse, midwife, engineer, ninja or rockstar. Because of this, you know you can trust what I say about social media because I'm not trying to sell it to you. You can also ignore it because you're not paying me.</p>

<p>I don't tend to say much on the subject of Twitter. I also don't tend to say that much on <a href="http://twitter.com/thingsinjars">Twitter</a> itself. That said, I do spend a lot of time on the Internet so here are some things you should stop doing now. Like, right now. Call it ‘Social media bad practice’ if you will, or ‘Tips and Tricks for a Tidier Tweet’ if that's the kind of thing you're into. Whatever, stop doing these:</p>

<h2>Autotweeting from 3rd party apps</h2>
<p>When you use one of the many apps that track your weight, book-reading habits, location, tweetability or shoe-size, disable the 'post to Twitter?' option, please. When I see these posts, all I read is either:</p>
<p>“According to amIanEejit.com, I'm an Eejit. Are you? Try it now.”</p>
<p>or</p>
<p>“I need public validation. Did I do good? Did I?”</p>

<h2>Tweeting a shortened URL which performs an action on the logged-in user's account</h2>
<p>Of course, fault for this should also be spread equally between the tweeter, the website which allows GET operations to modify data and the user who isn't wary enough of shortened URLs to expand them first. The person who creates the shortened URL without being aware of the consequences is to blame <em>and</em> an eejit. If you're not sure what I'm talking about, here's an example:</p>
<ol>
<li>You have an account on website X which you are logged into</li>
<li>I have an account on website X which I am logged into</li>
<li>Website X allows you to delete your account by going to www.example.com/deletemyaccount.php</li>
<li>You copy that URL and shorten it using bit.ly</li>
<li>You tweet “Hey, this is what I think of Website X: http://bit.ly/madeupthing”</li>
<li>I click the link</li>
<li>My account on Website X gets deleted</li>
<li>I stab you with pencils.</li>
</ol>

<h2>Using inappropriate hashtags to piggy-back on an unrelated discussion</h2>
<p>Some people use #hashtags as tweet meta data providing an extra piece of context on the tweet – “Om nom nom #fridaymorningbaconroll” – while others use them to create fluid, transient chatrooms. Where in the past you'd have used IRC and created a relevant room, using Twitter and a hashtag, you can jump into a conversation and out again without even trying. If you attempt to barge your way in with irrelevant comments, advertising nonsense or general eejicy, you act no better than an out-and-out-spammer and I don't follow no spammers.</p>

<h2>Flooding followers with real-time reporting</h2>
<p>Use a separate account for this kind of thing. <a href="http://www.macrumors.com">Macrumors</a> do this whenever there's one of those big Steve Jobs parties – if you want to follow all the info, follow the <a href="http://twitter.com/macrumorslive">@macrumorslive</a> account. Similarly, <a href="http://fridaymix.com">Fridaymix</a> do the same thing. Discussions happen with the <a href="http://twitter.com/fridaymix">@fridaymix</a> account while the announcements of what is currently being played come from <a href="http://twitter.com/fridaymixdj">@fridaymixdj</a>.</p>
<h3>Related: Retweeting your other account.</h3>
<p>If I wanted to follow the other account, I'd follow the other account.</p>
<h3>Also related: Retweeting your own main account</h3>
<p>I heard you. Don't be the guy at the party with one punchilne that you tell again and again. I already know that guy. I don't follow him on Twitter.</p>

<h2>Posting quotes from conference presentations without context or grammar</h2>
<h3>This doubly applies if the quote sounds like a half-hearted Zen koan.</h3>
<p>“Listen to the youth. They have younger voices.”</p>
<p>“Use torches to light the way. Technology is your torch.”</p>

<h3>This triply applies if you use antimetabole</h3>
<p>“Don't follow the herd, herd the followers.”</p>
<p>“Don't live beyond means, have meaning beyond living.”</p>

<p>Of course, the worst is probably tweeting about your own blog post in which you discuss tweeting as if it actually matters.</p>      </div>
]]></description>
<pubDate>Wed, 06 Oct 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>...and a salesman, too.</title>
<link>http://thingsinjars.com/post/300/and-a-salesman-too/</link>
<guid>http://thingsinjars.com/post/300/and-a-salesman-too/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-300">
        <p><a href="http://thingsinjars.com/post/300/and-a-salesman-too/">...and a salesman, too.</a></p>
It seems to be a fundamental aspect of the world that, whatever you do for a living, you have to do that <em>and</em> be a salesman. When I say selling, I don't mean the purely business related contract-signing, accounting and banking aspect of sales, I mean <em>really</em> 'Selling yourself'. Marketing, if you will. The bit of the process that involves firm handshakes, giving presentations at conferences, reminding people at every opportunity that you are selling something they need. Even if they don't know they need it. Even if they don't need it.

You could be the greatest web developer known to the history of the interweb creating progressively-enhanced, backwards-compatible masterpieces of semantic mark-up which not only push the boundaries in the latest Webkit nightlies but still fly pixel-perfect in IE6 and you still wouldn't be able to run your own agency without selling your services.

Your iPhone app might be 'The Greatest App Ever Invented' combining the power of <a href="http://itunes.apple.com/us/app/google-mobile-app/id284815942?mt=8">Google</a>, the ease of use of <a href="http://itunes.apple.com/us/app/twitter/id333903271?mt=8">Twitter</a> and the graphics of <a href="http://itunes.apple.com/us/app/epic-citadel/id388888815?mt=8">Epic Citadel</a>. It might prove the <a href="http://en.wikipedia.org/wiki/Riemann_hypothesis">Riemann Hypothesis</a>, remind you of birthdays, cure cancer all while showing pictures of <a href="http://www.cutethingsfallingasleep.org/">cats falling asleep</a> but unless somebody actually knows it exists, it's no more useful than those apps that play the noises of bodily functions while simultanesouly being less succesful. By putting it in the iTunes Store you are technically selling it but you're not 'selling it'.

The same situation applies in every industry – writing books, making sandwiches, playing piano, juggling. Unless you are lucky enough to be 'discovered' by someone with the ability to sell but without anything to actually sell, there is no difference between you and everybody else in your field. Despite what you may have learnt in school, you do not get to the top of the class by being the smartest. You get to the top by putting your hand up when the teacher asks a question.

A few months back I saw an article entitled 'Talent does not go unrewarded'. I've seen too many shy, socially awkward developers who won't progress past the minimum acceptable salary for their job title to believe this. More accurately, I'd say 'Talent does not go unrecognised'. They don't get rewarded for their technical wizardry, they get rewarded for convincing their bosses they're worth more than they're currently being paid. For selling themselves.

Evan Williams' recent step down from CEO of Twitter to focus on product develpment strikes me as the developer's ideal – all the success and reward (financial and kudos) without the daily requirement to constantly sell. Of course, Twitter wouldn't have gotten to where it is if he hadn't been able to take on that role along the way.      </div>
]]></description>
<pubDate>Wed, 06 Oct 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Writing a Plex Plugin Part III</title>
<link>http://thingsinjars.com/post/299/writing-a-plex-plugin-part-iii/</link>
<guid>http://thingsinjars.com/post/299/writing-a-plex-plugin-part-iii/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-299">
        <p><a href="http://thingsinjars.com/post/299/writing-a-plex-plugin-part-iii/">Writing a Plex Plugin Part III</a></p>
<p>This is the final part of <a href="http://blah.thingsinjars.com/post/297/writing-a-plex-plugin-part-i/" title="geek - thingsinjars">my walkthrough</a> of the <a href="http://www.plexapp.com">Plex Media Server</a> <a href="http://transmissionbt.com">Transmission</a> plugin.</p>
<p>Right.</p>
<p>We've done the <a href="http://blah.thingsinjars.com/post/297/writing-a-plex-plugin-part-i/" title="geek - thingsinjars">required built-in functionality</a> (preference management, for instance) and <a href="http://blah.thingsinjars.com/post/298/writing-a-plex-plugin-part-ii/">the bits that talk to Transmission</a> itself. Basically, we're done. Anything else added here is just extra. That is, of course, the best reason to add stuff here. As I have <a href="http://thingsinjars.com/post/248/its-not-difficult-dont-make-it-difficult/">previously ranted</a> at length, there's no point doing anything if you aren't trying to do it as well as it possibly can be done. In this particular instance, that manifests itself in the ability to browse, search for and download torrents all within the Plex client interface.</p>

<h2>EZTV</h2>
<p>I love <a href="http://ezrss.it">EZTV</a>. It makes things easy. Previous versions of this plugin included an EZTV search but after rooting around in the source of the µTorrent plugin, I found some nifty code which turned me onto the clever XML parsing Plex can do.</p>
<p>Note: although some of this stuff looks clever, all the cleverness was done by the Plex dev team and the author of the µTorrent plugin. I'm a good copy-and-paster.</p>

<p>This function grabs the H2s from the page <a href="http://ezrss.it/shows/">http://ezrss.it/shows/</a>. If you go there, you'll see that the page lists every TV show in EZTV. The original µTorrent function listed everything but there are a lot of shows there now so it was actually taking a long time just to get that list. As they've split the page up by section, we can just grab the bits we want. This is going to be a full page in Plex (not a popup) so we're using a MediaContainer.</p>
<pre><code class="prettyprint">def TVShowListFolders(sender):
  dir = MediaContainer()</code></pre>

<p>Using the built-in XML module, we can simply pass in a URL and get back an object containing the hierarchical structure of the entire page. Seriously, how simple is this? As it's HTML, add in the option <code class="prettyprint">isHTML=True</code>.</p>
<pre><code class="prettyprint">  showsPage = XML.ElementFromURL(
                'http://ezrss.it/shows/', 
                isHTML=True, 
                errors='ignore'
              )</code></pre>

<p>Now that we have the whole page structure, take the chunks of the page we want. All the sections we want (and one we don't) are divs with the class 'block' so use that in xpath to pull them out.</p>
<pre><code class="prettyprint">  blocks = showsPage.xpath('//div[@class="block"]')</code></pre>

<p>The first block is the one we don't want (if you look at the page, it's the one that lists all the letters) so we remove it.</p>
<pre><code class="prettyprint">  blocks.pop(0)</code></pre>

<p>For each of the remaining blocks, find the text in the first H2. That is the letter title of the section ('A', 'B', 'C', etc). Add that to Plex as a menu item then return the entire list.</p>
<pre><code class="prettyprint">  for block in blocks:
    letter = block.xpath("h2")[0].text
    dir.Append(
      Function(
        DirectoryItem(
          TVShowListSubfolders,
          letter,
          subtitle=None,
          summary=None,
          thumb=R(ICON),
          art=R(ART)
        ),
        letter=letter
      )
    )
  return dir</code></pre>
<p>I hope I'm not the only one impressed with that (although I have a feeling I might be). Using just a couple of lines from the XML module and a sprinkle of xpath and we've got another menu, dynamically generated from a third-party website. If EZTV ever change their layout, it should be a simple matter of changing the xpath to match and we're done. Again.</p>

<p>We can now do the same again but this time, we only pull out a single section based on the letter passed in.</p>
<pre><code class="prettyprint">def TVShowListSubfolders(sender, letter):
  dir = MediaContainer()
  showsPage = XML.ElementFromURL(
                'http://ezrss.it/shows/',
                isHTML=True,
                errors='ignore'
              )
  blocks = showsPage.xpath(
            '//div[@class="block" and h2 = "%s"]' % letter
           )</code></pre>

<p>Remembering to ignore any 'back to top' links, write out a list of the shows in this section. These will call the TVEpisodeList method next.</p>
<pre><code class="prettyprint"> for block in blocks:
  for href in block.xpath('.//a'):
   if href.text != "# Top":
    requestUrl = "http://ezrss.it" + href.get("href") + "&mode=rss"
    dir.Append(
     Function(
      DirectoryItem(
       TVEpisodeList,
       href.text,
       subtitle=None,
       summary=None,
       thumb=R(ICON),
       art=R(ART)
      ),
      name=href.text,
      url=requestUrl
     )
    )
 return dir</code></pre>

<p>This lists all available torrents for the chosen show. By this point, you should be familiar with how this works. We're using the XML module to grab the page at the URL (this time it's an RSS feed so we don't need to parse it as HTML); we use XPath to iterate through the items in the feed; we generate a menu item from the data which will call a function when selected; we append that to a MediaContainer then return the whole thing to Plex. Done. The AddTorrent function was defined <a href="http://blah.thingsinjars.com/post/298/writing-a-plex-plugin-part-ii/">higher up</a>.</p>
<pre><code class="prettyprint">def TVEpisodeList(sender, name, url):
 dir = MediaContainer()
 feed = XML.ElementFromURL(url, isHTML=False, errors='ignore').xpath("//item")
 for element in feed:
  title = element.xpath("title")[0].text
  link = element.xpath("link")[0].text
  dir.Append(
   Function(
    DirectoryItem(
     AddTorrent,
     title,
     subtitle=None,
     summary=None,
     thumb=R(ICON),
     art=R(ART)
    ),
    torrentUrl=link
   )
  )
 return dir</code></pre>

<h2>Adult considerations...</h2>
<p>There is currently a section in the plugin which will allow you to search IsoHunt. This might get dropped in future versions of the plugin as results from IsoHunt are almost exclusively...ahem...adult, regardless of search terms. Sure, that might be exactly what you were looking for but if you were actually looking for Desperate Housewives, you might be surprised when your file comes down and it's actual 'desperate housewives'...</p>

<h2>Search EZTV</h2>
<p>The final part is a straightforward search of EZTV. The interesting thing to note is that this uses a different type of menu item. Where normally, you'd use a DirectoryItem in a Function, this uses an InputDirectoryItem in a Function. This type of menu item will pop open an on-screen keyboard before calling the target function giving you the opportunity to grab some user input.</p>

<p>It's appended to the menu in the usual way:</p>
<pre><code class="prettyprint"> dir.Append(
  Function(
   InputDirectoryItem(
    SearchEZTV,
    L('MenuSearchTV'),
    "Search the TV shows directory",
    summary="This will use EZTV to search.",
    thumb=R(SEARCH),
    art=R(ART)
   )
  )
 )</code></pre>
<p>By the way, I think there's a minor bug in the InputDirectoryItem in that it doesn't like it when subtitle is passed as a named argument. I should probably file that as a bug with <a href="http://elan.plexapp.com">Elan</a>.</p>

<p>When the user has entered their input and submitted, the named Function <code class="prettyprint">SearchEZTV</code> is called with the standard argument <code class="prettyprint">sender</code> and the extra argument <code class="prettyprint">query</code> containing the user's input.</p>
<p>This function was a lot longer in the previous version of the Framework. It was so much simpler this time round.</p>
<pre><code class="prettyprint">def SearchEZTV(sender, query=None):
  dir = MediaContainer()
  url = "http://ezrss.it/search/index.php?simple&mode=rss&show_name="
  if query != None:
   url += "%s" % query
  feed = XML.ElementFromURL(
          url, 
          isHTML=False, 
          errors='ignore'
         ).xpath("//item")
  if feed == None:
    return MessageContainer("Error", "Search failed")
  if len(feed) == 0:
    return MessageContainer("Error", "No results")
  for element in feed:
    title = element.xpath("title")[0].text
    category = element.xpath("category")[0].text
    link = element.find("enclosure").get("url")
    size = prettysize(int(element.find("enclosure").get("length")))
    dir.Append(
      Function(
       DirectoryItem(
        AddTorrent,
        title,
        subtitle=None,
        summary="Category: %s\nSize: %s" % (category,size),
        thumb=R(ICON),
        art=R(ART)
       ),
      torrentUrl=link
     )
    )
  return dir</code></pre>
  
<h2>Done</h2>
<p>That's it. The only other little thing to mention is how handy it is to use the built-in Log function. The first argument is a standard Python string, the second is 'Should this only turn up in the console when in debug mode?' to which the answer will almost always be 'True'. There is a third argument but unless you're messing with character encodings, you don't need to worry about it.</p>
<pre><code class="prettyprint">Log("Message to log is: %s %d" % (errorString, errorCode), True)</code></pre>

<h2>Go, make...</h2>
<p>If you made it to the end here, you're probably either keen to start making your own Plex plugins or <a href="http://www.flickr.com/photos/photojennic/">my wife</a> who I am going to get to proofread this. Assuming you're the former, here are some handy links:</p>

<ul>
	<li style="margin:0;"><h3><a href="http://dev.plexapp.com/docs/">Online plugin development manual</a></h3>
	<p>There are plenty of bits missing but it's still the best reference available for the framework.</p></li>
	<li style="margin:0;"><h3><a href="http://forums.plexapp.com/">Plex forums</a></h3>
	<p>Particularly the <a href="http://forums.plexapp.com/index.php?/forum/42-media-server-plugins/">Media Server Plugins forum</a></p></li>
	<li style="margin:0;"><h3><a href="https://plexapp.lighthouseapp.com/projects/31804-plex-plug-ins/overview">Plex Plugins Lighthouse</a></h3>
	<p>This is where bugs are filed, suggestions made and final plugin submission happens. It's handy for picking little tips if someone else has had the same problem as you.</p></li>
</ul>
<p>If you want to use the plugin, it's available in 'Plex Online' in Plex/Nine or 'Plex App Store' in Plex/Eight. If you'd like to read through the complete source, you can download the zipped .Bundle.
<p><a href="http://thingsinjars.com/uploaded/other/Transmission.bundle.zip">Transmission Plugin for Plex Media Server v1.0 [Zip - 1.1MB]</a></p>
      </div>
]]></description>
<pubDate>Thu, 30 Sep 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Writing a Plex Plugin Part II</title>
<link>http://thingsinjars.com/post/298/writing-a-plex-plugin-part-ii/</link>
<guid>http://thingsinjars.com/post/298/writing-a-plex-plugin-part-ii/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-298">
        <p><a href="http://thingsinjars.com/post/298/writing-a-plex-plugin-part-ii/">Writing a Plex Plugin Part II</a></p>
<p>This is part two of <a href="http://blah.thingsinjars.com/post/297/writing-a-plex-plugin-part-i/" title="geek - thingsinjars">my walkthrough</a> of the <a href="http://www.plexapp.com">Plex Media Server</a> <a href="http://transmissionbt.com">Transmission</a> plugin.</p>
 
<p>The previous part dealt with the basic required functions and preparing the main menu. This bit goes through the torrent control and the next will cover the built-in site-scraping functionality. To be honest, I'm not sure how much of this middle section will be of use to anyone but other torrent client plugin makers. The cool stuff really happens in the next one. Think of this as the difficult second album that you have to listen to before the return-to-form third.</p>
 
<h2>Listing the torrents</h2>
<p>This is the main interface to Transmission. Using the <code class="prettyprint">RTC</code> method from before, this prepares a request to send via HTTP and reacts depending on the result (or error) we get back. First of all, we say we want information ('torrent-get') and we specify what info we want (the 'fields')</p>
<pre><code class="prettyprint">def TorrentList(sender):
  error, result  = RTC("torrent-get",
    { "fields": [
      "hashString","name","status",
      "eta","errorString",
      "totalSize","leftUntilDone","sizeWhenDone",
      "peersGettingFromUs",  "peersSendingToUs",  "peersConnected",
      "rateDownload",      "rateUpload",
      "downloadedEver",    "uploadedEver"
    ] }
  )</code></pre>
<p>If we get an error back, we check what it was.</p>
<pre><code class="prettyprint">  if error != None:
    if error != "Connection refused":
      return MessageContainer(
          "Transmission unavailable",
          "There was an unknown error."
      )
    else:
      return MessageContainer(
          "Transmission unavailable",
          "Please make sure Transmission is installed and running."
      )</code></pre>
 
<p>Now we have our information, we create a MediaContainer to display it. We'll be building these entries up as if they were standard library MediaItems although the final action will not be to play them.</p>
<pre><code class="prettyprint">  elif result["torrents"] != None:
    dir = MediaContainer()</code></pre>
 
<p>For each set of torrent information we get back, we need to prepare the info and make it pretty.</p>
<pre><code class="prettyprint">    for torrent in result["torrents"]:
      progress    = 100;
      summary = ""
 
      if torrent["errorString"]:
        summary += "Error: %s\n" % (torrent["errorString"])</code></pre>
 
<p>If we have some time until we're done and we're not seeding, display the progress as "12.3 MB of 45.6 GB (0%)". We add this to the MediaItem's summary field. This is where we use the <code class="prettyprint">prettysize</code> and <code class="prettyprint">prettyduration</code> functions we imported at the top. They take a computer-friendly value (1048576 bytes) and return a human-friendly one (1MB).</p>
<pre><code class="prettyprint">  if torrent["leftUntilDone"] > 0 and
    torrent["status"] != TRANSMISSION_SEEDING:
    progress = ((torrent["sizeWhenDone"] - torrent["leftUntilDone"]) /
          (torrent["sizeWhenDone"] / 100))
 
    summary += "%s of %s (%d%%)\n" % (
        prettysize(torrent["sizeWhenDone"] - torrent["leftUntilDone"]),
        prettysize(torrent["sizeWhenDone"]), progress
      )</code></pre>
 
 
<p>Similarly, if there's an estimated time until the file is finished downloading, add that to the summary as "3 days remaining"</p>
<pre><code class="prettyprint">    if torrent["eta"] > 0 and torrent["status"] != TRANSMISSION_PAUSED:
      summary += prettyduration(torrent["eta"]) + " remaining\n"
    else:
      summary += "Remaining time unknown\n"</code></pre>
 
<p>Display download status ("Downloading from 3 of 6 peers") and download and upload rates ("Downloading at 3KB/s, Uploading at 1KB/s").</p>
<pre><code class="prettyprint">  if torrent["status"] == TRANSMISSION_DOWNLOADING:
    summary += "Downloading from %d of %d peers\n" % (
      torrent["peersSendingToUs"],
      torrent["peersConnected"])
    summary += "Downloading at %s/s\nUploading at %s/s\n" % (
      prettysize(torrent["rateDownload"]),
      prettysize(torrent["rateUpload"]))</code></pre>
    
<p>For all other downloading statuses, we don't need extended information so we just return a human-friendly version of the status we get back (we do this via another method below).</p>  
<pre><code class="prettyprint">  else:
    summary += TorrentStatus(torrent)</code></pre>
 
<p>If we're seeding (the torrent has finished downloading and we're just uploading now), write out information about the uploading.</p>
<pre><code class="prettyprint">  else:
    if torrent["status"] == TRANSMISSION_SEEDING:
      summary += "Complete\n"
      progress=100
      if torrent["downloadedEver"] == 0:
        torrent["downloadedEver"] = 1</code></pre>
 
<p>"45.6GB, uploaded 22.8GB (Ratio 0.50)" and some detail about the people we're uploading to.</p>
<pre><code class="prettyprint">  summary += "%s, uploaded %s (Ratio %.2f)\n" % (
    prettysize(torrent["totalSize"]),
    prettysize(torrent["uploadedEver"]),
    float(torrent["uploadedEver"]) / float(torrent["downloadedEver"]))
  if torrent["status"] == TRANSMISSION_SEEDING:
    summary += "Seeding to %d of %d peers\n" % (
      torrent["peersGettingFromUs"],
      torrent["peersConnected"])
    summary += "Uploading at %s/s\n" % (
      prettysize(torrent["rateUpload"]))</code></pre>
 
<h3>Icon generation</h3>
<p>The next addition was a bit of a tricky point for this version of the plugin. Previous versions generated the thumbnail icon dynamically using the Python Imaging Library (PIL). It would create a progress bar showing the exact percentage and write the name of the file on the icon. In order to be able to achieve this, PIL had to be imported which generated a whole bunch of deprecation warnings. There are rumours that a future version of the plugin framework will include some functionality to generate images on-the-fly (possibly a variation of PIL itself) but until then, I decided the best way forward would be to generate the images by hand and include them in the plugin. This meant that I could either generate 101 images (0% - 100%) or display the percentage rounded off. In order to save space, I went with rounding to the nearest 10%.</p>
<pre><code class="prettyprint">  nearest = int(round(progress/10)*10)</code></pre>
 
<p>The last thing to do in this loop (remember, we're still looping through the torrent information we received all the way back up at the top of the page) is to actually add this item. It is added as a PopupDirectoryItem so that selecting it will display a context menu of action choices specified in the TorrentInfo method below. With that, we also add the summary we've spent so long crafting, the percentage icon as the thumb and a couple of extra bits of information to help later functions know what to do.</p>
<pre><code class="prettyprint">  dir.Append(
    Function(
      PopupDirectoryItem(
        TorrentInfo,
        torrent["name"],
        summary=summary,
        thumb=R("%s.png" % nearest)
      ),
      name = torrent["name"],
      status = torrent["status"],
      hash = torrent["hashString"]
    )
  )</code></pre>
 
<p>To finish this menu, we add the same functions that are available to individual torrents but acting on all – 'Pause all' and 'Resume all' – then return the menu to Plex for display.</p>
<pre><code class="prettyprint">  dir.Append(
    Function(
      DirectoryItem(
        PauseTorrent,
        L('MenuPauseAll'),
        subtitle=None,
        summary=None,
        thumb=R(PAUSE),
        art=R(ART)
      ),
      hash='all'
    )
  )
  dir.Append(
    Function(
      DirectoryItem(
        ResumeTorrent,
        L('MenuResumeAll'),
        subtitle=None,
        summary=None,
        thumb=R(RESUME),
        art=R(ART)
      ),
      hash='all'
    )
  )
  return dir</code></pre>
 
<p>Here's the TorrentStatus lookup. Again, this uses the built-in localisation function 'L' to display the text and, again, I still haven't actually translated any of it so there's still only english. I must get round to that eventually.</p>
<pre><code class="prettyprint">def TorrentStatus(torrent):
  if torrent == None or torrent["status"] == None:
    return L('TorrentStatusUnknown')
  elif torrent["status"] == TRANSMISSION_WAITING:
    return L('TorrentStatusWaiting')
  elif torrent["status"] == TRANSMISSION_CHECKING:
    return L('TorrentStatusVerifying')
  elif torrent["status"] == TRANSMISSION_PAUSED:
    return L('TorrentStatusPaused')
  elif torrent["status"] == TRANSMISSION_DOWNLOADING:
    return L('TorrentStatusDownloading')
  elif torrent["status"] == TRANSMISSION_SEEDING:
    return L('TorrentStatusSeeding')
  else:
    return L('TorrentStatusUnknown')</code></pre>
 
<h2>Torrent action menu</h2>
<p>This is the popup menu displayed when you select one of the listed torrents. The only thing to notice from these is that the option to pause is only shown for active torrents and the option to resume is only shown for paused torrents. The hash mentioned here is the id of the torrent which will be needed later.</p>
<pre><code class="prettyprint">def TorrentInfo(sender, name, status, hash):
  dir = MediaContainer()
  dir.Append(
    Function(
      DirectoryItem(
        ViewFiles,
        L('MenuViewFiles'),
        subtitle=None,
        summary=None,
        thumb=R(ICON),
        art=R(ART)
      ),
      hash=hash
    )
  )
  if status == TRANSMISSION_PAUSED:
    dir.Append(
      Function(
        DirectoryItem(
          ResumeTorrent,
          L('MenuResume'),
          subtitle=None,
          summary=None,
          thumb=R(ICON),
          art=R(ART)
        ),
        hash=hash
      )
    )
  else:
    dir.Append(
      Function(
        DirectoryItem(
          PauseTorrent,  
          L('MenuPause'),      
          subtitle=None,
          summary=None,
          thumb=R(ICON),
          art=R(ART)
        ),
        hash=hash
      )
    )
    dir.Append(
      Function(
        DirectoryItem(
          RemoveTorrent,
          L('MenuRemove'),
          subtitle=None,
          summary=None,
          thumb=R(ICON),
          art=R(ART)
        ),
        hash=hash
      )
    )
    dir.Append(
      Function(
        DirectoryItem(
          DeleteTorrent,
          L('MenuDelete'),
          subtitle=None,
          summary=None,
          thumb=R(ICON),
          art=R(ART)
        ),
        hash=hash
      )
    )
  return dir</code></pre>
 
<h2>Torrent action functions</h2>
<p>Each of the torrent action functions called (<code class="prettyprint">ViewFiles</code>, <code class="prettyprint">ResumeTorrent</code>, etc.) could have been references to a more generic function with an action option passed in but I decided to keep them distinct and separate so that any extra customisation that might be done later would be easier to do rather than hacking it in. This isn't so much a problem with this plugin but if this were to be adapted for another torrent client, there might be specific hoops that needed jumped through.</p>
<p>I won't go through each of them in detail as they are all very similar. Instead, I'll just describe one of them – <code class="prettyprint">RemoveTorrent</code>.</p>
 
<p>Each Function menu item (pretty much every menu item in this plugin) takes at least one argument: <code class="prettyprint">sender</code>. This tells Plex where it's supposed to return control after it's finished here. The second argument is the id of the torrent we want to act on.</p>
<pre><code class="prettyprint">def RemoveTorrent(sender, hash):</code></pre>
  
<p>We define the action to perform and the arguments to pass to Transmission.</p>
<pre><code class="prettyprint">  action = "torrent-remove"
  arguments = { "ids" : hash }</code></pre>
  
<p>Call Transmission's RPC via the RTC method defined earlier catching the results and any errors returned.</p>
<pre><code class="prettyprint">  error, result = RTC(action, arguments)</code></pre>
 
<p>If there's an error, any error, display it. Otherwise, display a success method. Both of these are displayed as a popup MessageContainer.</p>
<pre><code class="prettyprint">  if error != None:
    return MessageContainer("Error", error)
  else:
    return MessageContainer("Transmission", L('ActionTorrentRemoved'))</code></pre>
 
<p>Okay, so the middle section of the plugin might not be that interesting. Next time I'll cover the clever built-in XML parsing bits and everything'll be cool again. I promise.</p>      </div>
]]></description>
<pubDate>Thu, 23 Sep 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Writing a Plex Plugin Part I</title>
<link>http://thingsinjars.com/post/297/writing-a-plex-plugin-part-i/</link>
<guid>http://thingsinjars.com/post/297/writing-a-plex-plugin-part-i/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-297">
        <p><a href="http://thingsinjars.com/post/297/writing-a-plex-plugin-part-i/">Writing a Plex Plugin Part I</a></p>
<p>In my awesome home cinema setup (about which I'll need to blog sometime), I use many pieces of inter-connected software and hardware. The hub, though, is the OS X computer in the middle running the <a href="http://www.plexapp.com">Plex Media Server</a> and the <a href="http://transmissionbt.com">Transmission BitTorrent client</a>. This post describes the plugin which ties them together.</p>

<p>I've just released version 1.0 of the Transmission plugin for the Plex Media Server. As with all good software projects, there were actually many releases before 1.0 but I thought this was the right time to write up a walk-through of what the code looks like and does. I didn't write the initial version of the plugin but I've maintained it since v0.7 and now pretty much rewritten everything a couple of times. I'll post my walkthrough in a few installments because it's quite long.</p>

<p>The code as it currently stands (v1.0) is available for download below but within a few days you should also be able to download it within 'Plex Online'</p>
<p><a href="http://thingsinjars.com/uploaded/other/Transmission.bundle.zip">Transmission Plugin for Plex Media Server v1.0</a></p>
<p>As Michael A. pointed out in the comments, I haven't actually mentioned anywhere below what it is that the plugin does. For a quick overview, check out the <a href="http://wiki.plexapp.com/index.php/Transmission">Plex wiki Transmission page</a>.</p>



<p>This plugin is built to be compatible with Plex Plugin Framework v1 which initially looked like quite a major change from the previous version of the framework but isn't really that different. For Plex plugins, every time an action is performed, the system generates a URL and passes it down through its own menu structure until it gets to a plugin that handles that URL. The plugin then deals with the info in the URL however it likes. In the previous versions of this plugin, the URL was parsed manually and split into strings separated by '/'</p>

<p>For example the URL:</p>
<pre><code class="prettyprint">/video/transmission/id/status/action/</code></pre>

<p>would first cause Plex to look in its 'video' menu item and find the plugin that said it could handle 'transmission' URLs. The plugin would take the rest of the string and separate it out. First contact the Transmission application, ask for all information about the torrent called 'id', check its 'status' and then perform the 'action' if possible.</p>

<p>The new plugin does pretty much the same except I no longer manually parse the URL. The plugin still registers with Plex to say it can handle URLs starting '/video/transmission' but then it passes functions through instead of URL-catching menu items. If you're familiar with JavaScript, it's like passing an anonymous function to handle something instead of catching the event manually.</p>

<p>Anyway, here's the python code with a running commentary:</p>

<h2>Imports</h2>
<p>First we import the Plex Media Server framework:</p>
<pre><code class="prettyprint">from PMS import *
from PMS.Objects import *
from PMS.Shortcuts import *</code></pre>

<p>These are a couple of handy functions from the very first version of the plugin which make the outputs much more readable.</p>
<pre><code class="prettyprint">from texttime  import prettyduration
from textbytes  import prettysize</code></pre>

<p>This next line actually causes Plex to issue a warning. These libraries won't all be available in the next version of the framework. Instead of urllib and urllib2, developers are to use the built-in HTTP module. Unfortunately, HTTP doesn't allow access to the headers of responses and the Transmission authentication system relies on exchanging a session ID via headers.</p>
<pre><code class="prettyprint">import urllib,urllib2,base64</code></pre>

<h2>Declarations</h2>
<p>Set up some constants to save typing later on</p>
<pre><code class="prettyprint">PLUGIN_PREFIX = "/video/transmission"
PLUGIN_TITLE = "Transmission"</code></pre>

<p>This is the first call to the Localisation module. Plex plugins allow for complete string localisation via a JSON file (I've only included English in this version because my torrent-related German and Japanese are poor). This will look in the JSON file for the key 'Title' and return whatever value is associated with it (or 'Title' if there is none).</p>
<pre><code class="prettyprint">NAME = L('Title')</code></pre>

<p>More shorthand</p>
<pre><code class="prettyprint">ART        = 'art-default.jpg'
ICON      = 'icon-default.png'
SETTINGS  = 'settings-hi.png'
PAUSE      = 'pause-hi.png'
RESUME    = 'resume-hi.png'
SEARCH    = 'search-hi.png'
TV        = 'tv-hi.png'

TRANSMISSION_WAITING      = 1
TRANSMISSION_CHECKING      = 2
TRANSMISSION_DOWNLOADING  = 4
TRANSMISSION_SEEDING      = 8
TRANSMISSION_PAUSED        = 16</code></pre>


<h2>Definitions</h2>
<h3>Required</h3>
<p>Here is where we start the plugin code. This is one of the standard functions which gets called when the plugin is initialised.</p>
<pre><code class="prettyprint">def Start():</code></pre>
  
<p>Tell Plex we can handle '/video/transmission' URLs and that our main function is called 'MainMenu'</p>
<pre><code class="prettyprint">  Plugin.AddPrefixHandler(
    PLUGIN_PREFIX, 
    MainMenu, 
    PLUGIN_TITLE, 
    ICON, 
    ART)

  MediaContainer.art = R(ART)
  MediaContainer.title1 = NAME
  DirectoryItem.thumb = R(ICON)</code></pre>


<p>Another standard function, this handles the preferences. To connect to Transmission, you need the URL and port it is running on (127.0.0.1:9091 if it's on the same machine as the Plex Media Server) and the username and password if you have set them.</p>
<pre><code class="prettyprint">def CreatePrefs():
    Prefs.Add(id='hostname', type='text', default='127.0.0.1:9091', label='Hostname')
    Prefs.Add(id='username', type='text', default='', label='Username')
    Prefs.Add(id='password', type='text', default='', label='Password', option='hidden')</code></pre>


<p>This is called immediately after the preferences dialog is submitted. This is the most basic checking you can do but it could include a call to Transmission to verify the info provided.</p>
<pre><code class="prettyprint">def ValidatePrefs():
    u = Prefs.Get('username')
    p = Prefs.Get('password')
    h = Prefs.Get('hostname')
    if( h ):
        return MessageContainer(
            "Success",
            "Info provided is ok"
        )
    else:
        return MessageContainer(
            "Error",
            "You need to provide url, username, and password"
        )</code></pre>

<p>You'll notice the return here is a MessageContainer. That's Plex's version of an alert. It doesn't generate a new page, just pops up a little window.</p>

<h3>Custom</h3>
<p>That was the end of the predefined functions, the plugin proper starts here. As Transmission requires a username, password and a short-lived session ID (since Transmission v1.53) to perform actions, we define a function which will attempt to make a connection with just username & password. Transmission will then send back a 409 Conflict response to basically say "Urk, that's not quite right. If you want to talk to me, you'll need this:" and give us our session ID in a header.</p>
<pre><code class="prettyprint">def GetSession():
  h = Prefs.Get('hostname')
  u = Prefs.Get('username')
  p = Prefs.Get('password')
  url = "http://%s/transmission/rpc/" % h
  request = { "method" : "session-get" }
  headers = {}
  if( u and p and h):
    headers["Authorization"] = "Basic %s" % 
      (base64.encodestring("%s:%s" % (u, p))[:-1])
    try:
      body = urllib2.urlopen(
        urllib2.Request(
          url, 
          JSON.StringFromObject(request), 
          headers
        )
      ).read()
    except urllib2.HTTPError, e:
      if e.code == 401 or e.code == 403:
        return L('ErrorInvalidUsername'), {}
      return e.hdrs['X-Transmission-Session-Id']
    except:
      return L('ErrorNotRunning'), {}</code></pre>

<p>Once the HTTP module allows access to returned headers, we will be able to use something like this to set global authorisation once and forget about it:</p>
<pre><code class="prettyprint">response = HTTP.Request(
    url, 
    { "method" : "session-get" }, 
    headers={}, 
    cacheTime=None
    )
HTTP.SetPassword(h,u,p)
HTTP.SetHeader(
  'X-Transmission-Session-Id', 
  response.headers['X-Transmission-Session-Id']
  )</code></pre>

<h3>Remote Transmission Calls</h3>
<p>This uses the RPC API of Transmission to do everything we need. We pass into the function 'What we want to do' and 'Who we want it done to' basically.</p>
<pre><code class="prettyprint">def RTC(method, arguments = {}, headers = {}):
  h = Prefs.Get('hostname')
  u = Prefs.Get('username')
  p = Prefs.Get('password')
  url = "http://%s/transmission/rpc/" % h

  session_id = GetSession()

  request = {
    "method":    method,
    "arguments":  arguments
  }</code></pre>

<p>Setup authentication here because, even though we've already gotten the session ID, it's useless if we don't actually use it.</p>
<pre><code class="prettyprint">  if( u and p ):
    headers["Authorization"] = "Basic %s" %
      (base64.encodestring("%s:%s" % (u, p))[:-1])

  headers["X-Transmission-Session-Id"] = session_id</code></pre>

<p>Now that we've built our instruction, throw it at Transmission and see what comes back.</p>
<pre><code class="prettyprint">  try:
    body = urllib2.urlopen(
      urllib2.Request(
        url, 
        JSON.StringFromObject(request), 
        headers)
      ).read()
  except urllib2.HTTPError, e:
    if e.code == 401 or e.code == 403:
      return L('ErrorInvalidUsername'), {}
    return "Error reading response from Transmission", {}
  except urllib2.URLError, e:
    return e.reason[1], {}

  result = JSON.ObjectFromString(body)</code></pre>

<p>We don't do error handling here as we want this function to be as generic as possible so we send anything we receive straight back to the calling function.</p>
<pre><code class="prettyprint">  if result["result"] == "success":
    result["result"] = None

  if result["arguments"] == None:
    result["arguments"] = {}

  return result["result"], result["arguments"]</code></pre>


<h2>Menus</h2>
<p>Right, we've got our helper methods set up, we're ready to make our first menu. This is the main one we mentioned earlier.</p>
<pre><code class="prettyprint">def MainMenu():</code></pre>
  
<p>You can set your menu screen to be laid out as “List”, “InfoList”, “MediaPreview”, “Showcase”, “CoverFlow”, “PanelStream” or “WallStream”. I'm keeping it simple here. Also, there's an extra call to <code class="prettyprint">GetSession</code> just to check everything's fine and wake the app up.</p>
<pre><code class="prettyprint">    dir = MediaContainer(viewGroup="List")
    GetSession()</code></pre>

<p>Pretty much all the menu items throughout the rest of this plugin are added using the same code which boils down to:</p>
<pre><code class="prettyprint">  dir.Append(
    Function(
      DirectoryItem(
        FunctionName,
        "Pretty Menu Item Name",
        subtitle="Short subtitle",
        summary="Longer menu item summary and description",
        thumb=R(ICON),
        art=R(ART)
      )
    )
  )</code></pre>

<p>Starting in the middle, this reads as:</p>
<ul>
<li>Create a <code class="prettyprint">DirectoryItem</code>.</li>
<li>When this item is selected, use the function <code class="prettyprint">FunctionName</code> to handle it.</li>
<li>Display the text <code class="prettyprint">"Pretty Menu Item Name"</code> for this item</li>
<li>Display the text <code class="prettyprint">"Short subtitle"</code> underneath this item (or None)</li>
<li>Display the text <code class="prettyprint">"Longer menu item summary and description"</code> for this item if required (or None)</li>
<li>Use the resource called ICON (mentioned above) as the icon for this item</li>
<li>Use the resource ART as the background </li>
<li>This is a <code class="prettyprint">Function</code> menu item</li>
<li>Finally, <code class="prettyprint">Append</code> this to the current menu</li>
</ul>

<p>The first two main menu items are built exactly like that:</p>
<pre><code class="prettyprint">  dir.Append(
    Function(
      DirectoryItem(
        TorrentList,
        "Torrents",
        subtitle=None,
        summary="View torrent progress and control your downloads.",
        thumb=R(ICON),
        art=R(ART)
      )
    )
  )
  dir.Append(
    Function(
      DirectoryItem(
        SearchTorrents,
          "Search for a torrent",
          subtitle=None,
          summary="Browse the TV shows directory or search for files to download.",
          thumb=R(SEARCH),
          art=R(ART)
        )
      )
    )</code></pre>

<p>This is a special 'Preferences' item that will call the Prefs functions defined at the top.</p>
<pre><code class="prettyprint">  dir.Append(
    PrefsItem(
      title="Preferences",
      subtitle="Set Transmission access details",
      summary="Make sure Transmission is running and 'Remote access' is enabled then enter the access details here.",
      thumb=R(SETTINGS)
    )
  )</code></pre>
  

<p>A quick note: the function 'R' here, much like the localisation one 'L' above is a built-in helper function. It handles resources such as images. If you're developing a plugin and can't understand why your icon images are caching so much, it might be because you're going through this function.</p>

  

<p>Send the directory (or Menu) back to Plex</p>
<pre><code class="prettyprint">    return dir</code></pre>

<p>The rest of the code deals with torrent control and some clever built-in site scraping functionality which I'll cover later.</p>      </div>
]]></description>
<pubDate>Thu, 16 Sep 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Maze 1k</title>
<link>http://thingsinjars.com/post/296/maze-1k/</link>
<guid>http://thingsinjars.com/post/296/maze-1k/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-296">
        <p><a href="http://thingsinjars.com/post/296/maze-1k/">Maze 1k</a></p>
<ul><li><a href="http://thingsinjars.com/widgets/js1k3.html">Random perfect maze generation, solution and rendering in 1011 bytes</a></li></ul>

<p>Okay, this is the last one for a while. Really.</p>

<p>Unlike my previous 1k JavaScript demos, I really had to struggle to get this one into the 1024 byte limit. I'd already done all the magnification and optimization techniques I knew of so I had to bring in some things which were new to me from <a href="http://qfox.nl/notes/111">qfox.nl</a> and <a href="http://benalman.com/news/2010/08/organ1k-js1k-contest-entry/">Ben Alman</a> and a few other places. This, combined with some major code refactoring, brought it down from 1.5k to just under 1. In the process, all possible readability was lost so here's a quick run through what it does and why.</p>

<h2>First up, a bunch of declarations.</h2>

<p>These are the colours used to draw the maze. Note, I used the shortest possible way to write each colour (<code class="prettyprint">red</code> instead of <code class="prettyprint">#F00</code>, <code class="prettyprint">99</code> instead of <code class="prettyprint">100</code>). The value stored in the maze array (mentioned later) refers not only to the type of block it is but also to the index of the colour in this array, saving some space.</p>
<pre><code class="prettyprint">u = ["#eff", "red", "#122", "rgba(99,255,99,.1)", "#ff0"],</code></pre>

<p>This is used for the number of blocks wide and high the maze is, the number of pixels per block, the size of the canvas and the redraw interval. Thanks to <a href="http://github.com/cowboy/js1k-organ1k/blob/master/organ1k.js">Ben Alman</a> for pointing out in his article how to best use a constant.</p>
<pre><code class="prettyprint"> c = 21,</code></pre>

<p>Here is the reference to the canvas. Mid-minification, I did have a bunch of function shortcuts here - <code class="prettyprint">r=Math.random</code>, for instance - but I ended up refactoring them out of the code.</p>
<pre><code class="prettyprint">m = document.body.children[0];</code></pre>

<p>For most of the time when working on this, the maze was wider than it was high because I thought that made a more interesting maze. When it came down to it, though, it was really a matter of bytesaving to drop the distinct values for width and height. After that, we grab the canvas context so we can actually draw stuff.</p>
<pre><code class="prettyprint">m.width = m.height = c * c;
h = m.getContext("2d");</code></pre>

<h2>The drawing function</h2>
<p>The generation and solution algorithm is quite nice and all but without this to draw it on the screen, it's really just a mathematical curio. This takes a colour, x and y and draws a square.</p>

<pre><code class="prettyprint">l = function (i, e, f) {
  h.fillStyle = i;
  h.fillRect(e * c, f * c, c, c)
};</code></pre>

<h2>Designing a perfect maze</h2>

<p>"You've got 1 minute to design a maze it takes 2 minutes to solve."<br />- Cobb, Inception.</p>

<p>Apologies for the unnecessary Inception quote. It's really not relevant.</p>

<p>Algorithmically, this is a fairly standard <a href="http://en.wikipedia.org/wiki/Maze_solving_algorithm">perfect maze</a> generator. It starts at one point and randomly picks a direction to walk in then it stops picks another random direction and repeats. If it can't move, it goes back to the last choice it made and picks a different direction, if there are no more directions, all blocks have been covered and we're done. In a perfect maze, there is a path (and only one path) between any two randomly chosen points so we can make the maze then denote the top left as the start and the bottom right as the end. This particular algorithm takes 2 steps in every direction instead of 1 so that we effectively carve out rooms and leave walls. You can take single steps but it's actually more of a hassle.</p>

<p>For more on how this kind of maze-generation works, check out this article on <a href="http://www.emanueleferonato.com/2008/12/06/perfect-maze-generation-tile-based-version/">Tile-based maze generation</a>.</p>

<h3>Blank canvas</h3>
<p>This is a standard loop to create a blank maze full of walls with no corridors. The <code class="prettyprint">2</code> represents the 'wall' block type and the colour <code class="prettyprint">#122</code>. The only really odd thing about this is the code <code class="prettyprint">f-->0</code> which is not to be read 'as f tends to zero' but is instead 'decrement f by 1, is it greater than zero?'</p>
<pre><code class="prettyprint">g = function () {
  v = [];  //our stack of moves taken so we can retrace our steps.
  for (i = [], e = c; e-- > 0;) {
    i[e] = [];
    for (f = c; f-- > 0;) i[e][f] = 2
  }</code></pre>

<p>By this point, we have a two-dimensional JavaScript array filled with 2s</p>

<h3>Putting things in</h3>
<pre><code class="prettyprint">  f = e = 1;    // our starting point, top left.
  i[e][f] = 0; // us, the zippy yellow thing</code></pre>

<h3>Carving out the walls</h3>
<p>This is our first proper <em>abuse</em> of the standard for-loop convention. You don't need to use the three-part structure for 'initialize variable; until variable reaches a different value; change value of variable'. It's 'do something before we start; keep going until this is false; do this after every repetition' so here we push our first move onto the stack then repeat the loop while there's still a move left on the stack.</p>
<pre><code class="prettyprint">  for (v.push([e, f]); v.length;) {</code></pre>

<p>P here is the list of potential moves from our current position. For every block, we have a look to see what neighbours are available then concatenate that cardinal direction onto the strong of potential moves. This was originally done with bitwise flags (the proper way) but it ended up longer. It's also a bit of a nasty hack to set p to be 0 instead of "" but, again, it's all about the bytes.</p>
<pre><code class="prettyprint">  p = 0;</code></pre>

<h3>Can we walk this way?</h3>
<p>These are all basically the same and mean 'if we aren't at the edge of the board and we're looking at a wall, we can tunnel into it.'.</p>
<pre><code class="prettyprint"> if (e < 18 && i[e + 2][f] == 2) p += "S"
 if (e >= 2 && i[e - 2][f] == 2) p += "N";
 if (f >= 2 && i[e][f - 2] == 2) p += "W";
 if (i[e][f + 2] == 2) p += "E";

 if (p) { //    If we've found at least one move
  switch (p[~~ (Math.random() * p.length)]) { // randomly pick one</code></pre>
<p>If there was anything to note from that last chunk, it would be that the operator <code class="prettyprint">~~</code> can be used to floor the current value. It will return the integer below thye current value.</p>

<h3>Take two steps</h3>
<p>This is a nice little hack. Because we're moving two spaces, we need to set the block we're on and the next one to be 0 (empty). This takes advantage of the right-associative unary operator 'decrement before' and the right associativity of assignment operators. It subtracts 1 from e (to place us on the square immediately above) then sets that to equal 0 then subtracts 1 from the new e (to put us on the next square up again) and sets that to equal the same as the previous operation, i.e. 0.</p>
<pre><code class="prettyprint">  case "N":
      i[--e][f] = i[--e][f] = 0;
      break;</code></pre>

<h3>Do the same for s, w and e</h3>
<pre><code class="prettyprint">    case "S":
      i[++e][f] = i[++e][f] = 0;
      break;
    case "W":
      i[e][--f] = i[e][--f] = 0;
      break;
    case "E":
      i[e][++f] = i[e][++f] = 0
    }</code></pre>

<p>Whichever move we chose, stick that onto the stack.</p>
<pre><code class="prettyprint">    v.push([e, f])</code></pre>

<h3>If there were no possible moves, backtrack</h3>
<pre><code class="prettyprint">  } else {
    b = v.pop(); //take the top move off the stack
    e = b[0]; // move there
    f = b[1]
  }
 }</code></pre>

<h3>End at the end</h3>
<p>At the very end, set the bottom right block to be the goal then return the completed maze.</p>
<pre><code class="prettyprint">  i[19][19] = 1;
  return i
};</code></pre>

<h2>Solver</h2>
<p>This is the solving function. Initially, it used the same algorithm as the generation function, namely 'collect the possible moves, randomly choose one' but this took too much space. So instead it looks for spaces north, then south, then west, then east. It follows the first one it finds.</p>
<pre><code class="prettyprint">s = function () {</code></pre>

<p>Set the block type of the previous block as 'visited' (rgba(99,255,99,.1) the alpha value makes the yellow fade to green).</p>
<pre><code class="prettyprint">  n[o][y] = 3;</code></pre>

<h3>A bit of ternary background</h3>
<p>This next bit looks worse than it is. It's the ternary operator nested several times. The ternary operator is a shorthand way of writing:</p>
<pre><code class="prettyprint">if ( statement A is true ) {
  Do Action 1
} else {
  Do Action 2
}</code></pre>

<p>In shorthand, this is written as:</p>

<pre><code class="prettyprint">Statement A ? Action 1 : Action 2;</code></pre>

<p>In this, however, I've replace Action 2 with another ternary operator:</p>

<pre><code class="prettyprint">Statement A ? Action 1 : ( Statement B ? Action 2 : Action 3 );</code></pre>

<p>And again, and again. Each time, it checks a direction, if it's empty, mark it as visited and push the move onto our stack.</p>
<pre><code class="prettyprint">(n[o + 1][y] < 2) ?
  (n[++o][y] = 0, v.push([o, y])) :
    (n[o - 1][y] < 2) ?
      (n[--o][y] = 0, v.push([o, y])) :
        (n[o][y - 1] < 2) ?
          (n[o][--y] = 0, v.push([o, y])) :
            (n[o][y + 1] < 2) ?
              (n[o][++y] = 0, v.push([o, y])) :</code></pre>

<h3>If none of the neighbours are available, backtrack</h3>
<pre><code class="prettyprint">                (b = v.pop(), o = b[0], y = b[1]);</code></pre>

<h3>Show where we are</h3>
<p>Finally, set our new current block to be yellow</p>
<pre><code class="prettyprint">  n[o][y] = 4;</code></pre>

<h3>Are we there yet?</h3>
<p>If we are at the bottom right square, we've completed the maze</p>
<pre><code class="prettyprint">  if (o == 19 && y == 19) {
  n = g();    //Generate a new maze
  o = y = 1; //Move us back to the top right
  s()     //Solve again</code></pre>

<p>If we haven't completed the maze, call the solve function again to take the next step but delay it for 21 milliseconds so that it looks pretty and doesn't zip around the maze too fast.</p>
<pre><code class="prettyprint">  } else setTimeout(s, c);</code></pre>

<h3>Paint it black. And green. And yellow.</h3>
<p>This is the code to render the maze. It starts at the top and works through the whole maze array calling the painting function with each block type (a.k.a. colour) and position.</p>
<pre><code class="prettyprint">    for (d in n) for (a in n[d]) l(u[n[d][a]], a, d)
  };</code></pre>

<h2>Start</h2>
<p>This is the initial call to solve the maze. The function s doesn't take any arguments but by passing these in, they get called before s and save a byte that would have been used if they had been on a line themselves.</p>
<pre><code class="prettyprint">s(n = g(), o = y = 1)</code></pre>

<h2>Done</h2>
<p>This little demo isn't as visually appealing as the <a href="http://thingsinjars.com/post/294/art-maker-1k/">Art Maker 1k</a> or as interactive as the <a href="http://thingsinjars.com/post/292/elementally-my-dear-javascript/">Spinny Circles 1k</a> but it is quite nice mathematically. There are now some astounding pieces of work in the <a href="http://js1k.com">JS1K demo competition</a>, though. I do recommend spending a good hour playing about with them all. Don't, however, open a bunch of them in the background at the same time. Small code isn't necessarily memory-efficient and you could quite easily grind your computer to a standstill.</p>      </div>
]]></description>
<pubDate>Thu, 19 Aug 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Art Maker 1K</title>
<link>http://thingsinjars.com/post/294/art-maker-1k/</link>
<guid>http://thingsinjars.com/post/294/art-maker-1k/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-294">
        <p><a href="http://thingsinjars.com/post/294/art-maker-1k/">Art Maker 1K</a></p>
<p>Even though the rules for <a href="http://js1k.com">js1k</a> only let me make one submission, I couldn't stop myself making another. This one is inspired by those pseudo-romantic pictures that you get <a href="http://fueledbyphotos.com/">all</a> <a href="http://icanread.tumblr.com/">over</a> <a href="http://everythingsright.com/">tumblr</a> that get reblogged endlessly (actually, it was inspired by the blog <a href="http://thatisntart.com/">That Isn't Art</a> by someone with the same opinion as myself).</p>

<p>It randomly creates a sentence, adds some softly-moving almost bokeh coloured-circles and look, I made an art! Wait for the sentence to change or click (or touch) to change it yourself.</p>

<p><a href="http://thingsinjars.com/widgets/js1k2.html">Art Maker 1k</a></p>

<p>And of course, don't forget the original <a href="http://thingsinjars.com/widgets/js1k.html">spinny-circles 1k</a></p>      </div>
]]></description>
<pubDate>Thu, 12 Aug 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>The quest for Extreme JavaScript Minification</title>
<link>http://thingsinjars.com/post/293/the-quest-for-extreme-javascript-minification/</link>
<guid>http://thingsinjars.com/post/293/the-quest-for-extreme-javascript-minification/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-293">
        <p><a href="http://thingsinjars.com/post/293/the-quest-for-extreme-javascript-minification/">The quest for Extreme JavaScript Minification</a></p>
<p>As <a href="http://blah.thingsinjars.com/post/292/elementally-my-dear-javascript/" title="Elementally, my dear JavaScript">described in detail previously</a>, I've recently taken part in the <a href="http://js1k.com">JS1K</a> competition where you have to squeeze something cool and clever into 1024 bytes of JavaScript. The quest to condense has become quite addictive and I found myself obsessing over every byte. This is the kind of stuff that the <a href="http://code.google.com/closure/compiler/">Closure Compiler</a> does quite well automatically but there are some cases where you just need to get in there and manually tweak.</p> 

<p>Here are some of the tricks I've picked up in my struggle for extreme minification:</p>

<h2>Basic improvements</h2>
<h3>Use short variable names.</h3> 
<p>This one's fairly obvious. A more useful addition to this is:</p>
<h3>Shorten long variable names.</h3>
<p>If you're going to be accessing an element more than once, especially if it's a built-in element like 'document', you'll save a few bytes every time you reference it if you create a shortened reference to it.</p>
<pre><code class="prettyprint">  document.body.style.overflow="hidden"
  document.body.style.background="red"
  (74 characters)
</code></pre>
<p>can shorten to</p>
<pre><code class="prettyprint">  d=document;b=d.body;s=b.style;
  s.overflow="hidden";
  s.background="red"
  (69 characters)
</code></pre>
<p>and any references to <code class="prettyprint">s</code> after are going to save 19 characters every time.</p>
<h3>Remove whitespace</h3>
<p>This one's so obvious, I don't need to mention it.</p>
<h3>Set Interval</h3>
<p>The extremely handy <code class="prettyprint">setInterval</code> function can take either a function or a string. If you give it an anonymous function declaration:</p>
<pre><code class="prettyprint">  setInterval(function(){x++;y--},10);
</code></pre>
<p>You will use up more characters than if you give it just the inside of the function as a string:</p>
<pre><code class="prettyprint">  setInterval('x++;y--',10);
</code></pre>
<p>But the outcome will be the same.</p>

<h2>Little-used aspects</h2>
<p>Not many people use JavScript's scientific notation unless they're doing scientific stuff but it can be a great byte saver. The number <code class="prettyprint">100</code> is equivalent to <code class="prettyprint">1 * 10^2</code> which is represented in JavaScript as 1E2. That's not a great saving for 100 but 1000 is 1E3, 10000 is 1E4. Every time you go up a factor of 10, you save 1 byte.</p>


<h2>Fight your good style tendencies</h2>
<p>In the war against space, you have to bite the bullet and accept that you may need to sacrifice some of your hard-earned practices. But only this once. Don't get in to the habit, okay?</p>
<h3>No zeroes</h3>
<pre><code class="prettyprint">  0.5  = .5
</code></pre>
<p>Yeah, it looks ugly but it works and saves a byte.</p>
<h3>Naked clauses</h3>
<pre><code class="prettyprint">  if {
    :
    :
  } else y
</code></pre>
<p>The <code class="prettyprint">y</code> looks so naked out there. No braces to keep it warm. But if you only have one statement in your else clause, you don't need them...</p>
<h3>No semi-final. . . final-semi. . . Semi-colon. No final colon.</h3>
<p>You don't need a semi-colon on your last line, even if it does make it look as though you've stunted its growth.</p>

<h2>The final few bytes</h2>
<h3>Operator precedence</h3>
<p>You don't need brackets. Brackets are handy for you as the programmer to remember what's going on when and to reduce ambiguity but if you plan correctly, most of the time you won't need brackets to get your arithmetic to work out.</p>
<pre><code class="prettyprint">  b.getMilliseconds()/(a*250) 
      is the same as
  b.getMilliseconds()/a/250 
</code></pre>
<h3>Shorthand notation</h3>
<pre><code class="prettyprint">  l=l+1;l=l%14;
  l++;l%=14;
  l=++l%14;
</code></pre>
<p>The three lines above are equivalent and in order of bytes saved.</p>
<h3>Shorthand CSS</h3>
<p>If you need to set some CSS values in your script, remember to pick the most appropriate short form. Instead of <code class="prettyprint">s.background='black'</code>, use  <code class="prettyprint">s.background='#000'</code> but instead of <code class="prettyprint">s.background='#F00'</code>, use <code class="prettyprint">s.background='red'</code>. In the same vein, the statements <code class="prettyprint">margin="0px"</code> and <code class="prettyprint">margin=0</code> mean the same but the latter saves bytes.</p>

<h2>Don't be generic</h2>
<p>One final thing to mention is that these little challenges are not the norm. If you find yourself trying to squeeze code down like this you're probably working on a very specific project. Use that to your advantage and see if there are any savings to be made by discarding your usual policies on code reuse. In the JS1K challenge, we're provided with a specific <a href="http://js1k.com/demo">HTML page</a> and an empty script tag. One good saving made here (and mentioned in my previous post) was the way I grabbed the reference to the canvas element. The standard method is to use the id assigned to the canvas.</p>
<pre><code class="prettyprint">  d.getElementById('c')
</code></pre>
<p>Which is a good generic solution. No matter what else was on the page, no matter what order stuff was in, this would return the canvas. However, we have a very specific case here and the canvas is always going to be in the same place - the first child of the body element. That means we can do this instead:</p>
<pre><code class="prettyprint">  b.children[0]
</code></pre>
<p>This makes use of the reference we grabbed to the body earlier. If the page were rearranged, this would stop working but as it won't, we've saved 8 bytes.</p>

<h2>In conclusion</h2>
<p>Yes, this is all quite silly but it's also fun and tricky. Attempting these kinds of challenges keep us developers mindful of what it is we actually do and that makes it an extremely productive silly hobby.</p>      </div>
]]></description>
<pubDate>Sun, 08 Aug 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Elementally, my dear JavaScript</title>
<link>http://thingsinjars.com/post/292/elementally-my-dear-javascript/</link>
<guid>http://thingsinjars.com/post/292/elementally-my-dear-javascript/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-292">
        <p><a href="http://thingsinjars.com/post/292/elementally-my-dear-javascript/">Elementally, my dear JavaScript</a></p>
<p><a href="http://www.angryrobotzombie.com">The Angry Robot Zombie Factory</a> launched its second iPhone/iPad app this week. I haven't mentioned it much yet because I spotted a minor typo in the final version after it had been approved so I submitted an update immediately. To get an early copy (like those misprinted stamps where the plane is upside down), go check out <a href="http://itunes.apple.com/app/the-elementals/id383675775?mt=8">The Elementals</a>. It's free, too. It's a simple, cartoonish periodic table.</p>
<p>Yesterday, the <a href="http://js1k.com">1k JavaScript demo contest</a> (<a href="http://twitter.com/#search?q=js1k">#js1k</a>) caught my eye. The idea is to create something cool using 1024bytes of JavaScript or less. I rootled around in the middle of The Elementals, grabbed the drawing function and 20 minutes later had made <a href="http://js1k.qfox.nl/demo/21">my entry</a>.</p>
<p>The code I submitted is quite minified but isn't obfuscated. When it's unfolded, you can follow the flow fairly easily.</p>

<pre><code class="prettyprint">var d = document,
b = d.body,
s = b.style,
w = innerWidth,
h = innerHeight,
v = b.children[0],
p = 2 * Math.PI,
Z = 3,
x = tx = w / 2,
y = ty = h / 2;
</code></pre>

<p>The above is a bunch of declarations. Using things like <code class="prettyprint">d = document</code> and <code class="prettyprint">b = d.body</code> allows reuse later on without having to resort to the full <code class="prettyprint">document.body.style</code> and saves a bunch of characters. When you've got such a small amount of space to play with, every character counts (mind you, the <a href="http://en.wikipedia.org/wiki/ZX81">ZX81</a> only had 1k of RAM and look what you could do with that). Now that I'm looking at it, I think I could have tidied this a bit more. Darn. The sneaky bit about this code is the way we grab the reference to the canvas. The code <code class="prettyprint">d.getElementById('c')</code> uses 21 characters but if we look at the provided HTML, we can use the fact that the canvas is the first child of the body element. The code <code class="prettyprint">b.children[0]</code> uses 13 characters instead.</p>

<pre><code class="prettyprint">s.margin = "0px";
s.background = "black";
s.overflow = "hidden";
v.width = w;
v.height = h;
t = v.getContext("2d");
</code></pre>

<p>This sets the provided canvas to be the full width and height of the window then grabs the drawing context of it so we can make pretty pictures.</p>

<pre><code class="prettyprint">zi = function () {
 Z++;
 Z %= 14
};
m = function (X) {
 return (X * 200) % 255
};
</code></pre>

<p>Functions to be reused later. <code class="prettyprint">zi</code> increases the number of spinning circles and is used by onmousedown and ontouchstart (oh yes, it works on the iPad, too). <code class="prettyprint">m</code> is a mapping of the index of the circle to a colour. The 200 is arbitrary. I played about a bit until I found some colour combinations I liked.</p>

<pre><code class="prettyprint"> d.ontouchstart = function (e) {
 zi();
 tx = e.touches[0].pageX;
 ty = e.touches[0].pageY
};
d.onmousemove = function (e) {
 tx = e.clientX;
 ty = e.clientY
};
d.onmousedown = zi;
</code></pre>

<p>Setting the event handlers.</p>

<pre><code class="prettyprint">function r() {
 t.globalCompositeOperation = 'lighter';
</code></pre>

<p>I played about with the <a href="https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html">various composite operations</a>. Lighter seemed the nicest.</p>

<pre><code class="prettyprint"> t.clearRect(0, 0, w, h);
 t.save();
 x = x + (tx - x) / 20;
 y = y + (ty - y) / 20;
 t.translate(x, y);
</code></pre>

<p>Originally, the circles followed the mouse pointer exactly but it lacked any life. By adding in this bit where the movement is delayed as if pulling against friction, it suddenly became a lot more fun and dynamic.</p>

<pre><code class="prettyprint"> var c = new Date();
 for (var i = 1; i       </div>
]]></description>
<pubDate>Wed, 04 Aug 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>PhoneGap - The Drupal of App development</title>
<link>http://thingsinjars.com/post/291/phonegap---the-drupal-of-app-development/</link>
<guid>http://thingsinjars.com/post/291/phonegap---the-drupal-of-app-development/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-291">
        <p><a href="http://thingsinjars.com/post/291/phonegap---the-drupal-of-app-development/">PhoneGap - The Drupal of App development</a></p>
<p>I'm a fan of <a href="http://drupal.org/">Drupal</a> even though I don't use it that often. I like that I can see exactly what's going on. I can easily follow the execution from URL request to page serve.</p>
<p>What I usually end up doing on any Drupal project is:</p>
<ol>
	<li>build the majority of the site in a few hours</li>
	<li>find one small piece of functionality missing that's absolutely essential</li>
	<li>dig into the core to make it happen</li>
	<li>find a simpler way of doing it and step out of the core a bit</li>
	<li>find an even simpler way and step back a bit more</li>
	<li>figure out how to do it in a single module file and put the core back the way it was.</li>
</ol>
<p>That probably seems utterly inefficient but it has served me well since Drupal 4 and it means I've got a really good picture in my head of the internal workflow.</p>
<p>This is in stark comparison to other systems, particularly some .NET CMSs where a request comes in, <em>something</em> happens and the page is served. There are even some PHP frameworks and CMSs where everything is so abstracted, the only way you can get an accurate picture of what is happening is to already <em>have</em> an accurate picture of what is happening.</p>
<p>I've used several different ones and I keep coming back to Drupal (also, recently, <a href="http://grabaperch.com/">Perch</a>, but that's besides the point here).</p>
<p><em>“What on earth does this have to do with PhoneGap?”</em> I hear you ask. Quite rightly, too.</p>
<p>When I was planning <a href="http://harmoniousapp.com/">Harmonious</a>, I looked at various frameworks for turning a combination of HTML, CSS & JavaScript into an app - <a href="http://www.phonegap.com/">PhoneGap</a>, <a href="http://www.appcelerator.com/">Appcelerator Titanium</a>, <a href="http://rhomobile.com/">Rhomobile</a>. Rhomobile (or the Rhodes Framework) is built on Ruby so I didn't investigate too far. That's not to say it's not a good framework, I couldn't say either way. The idea behind using one of these frameworks is to save you the time of having to learn Objective-C and seeing as I've only done very minimal amounts of Ruby, I'd be replacing 'learn Objective-C' with 'learn Ruby'. That said, I've always thought Ruby developers opinion of themselves was <a href="http://god.rubyforge.org/">slightly too high</a>.</p>
<p>The first framework I properly spent some time with was Appcelerator. It seemed quite shiny and I liked having single interface access to compilation for iPhone and Android but I wasn't so keen on having to sign up for an account with them for no obvious reason. Some further investigation suggested that this was so you could send your project to their servers for proprietary cross-platform compilation of your desktop app. This is less useful, however, if you're developing just for iPhone and Android as for both, you need the SDK installed locally and the compilation is done on your own machine.</p>
<p>The main thing that I wasn't comfortable with in Appcelerator was that there seemed to be a lot happening behind the scenes. This is not necessarily a bad thing, of course, but it started that little buzz in the back of my head that I get when working on .NET. When I press 'compile', I want to know exactly <em>what</em> it's doing. I want to know exactly how it takes my JavaScript and embeds it, when does it include its own API files and what do I change to make it do stuff it doesn't do by default?</p>
<p>After that, I moved to PhoneGap (version 0.8.3) and found myself immediately falling into my Drupal workflow. The app fell into place in less than an hour (with a liberal sprinkling of <a href="http://www.jqtouch.com/">jQTouch</a> and the <a href="http://www.glyphish.com/">Glyphish</a> icons). I then needed to take a screenshot and couldn't see an obvious way to do it but, due to the nature of PhoneGap being completely <a href="http://github.com/sintaxi/phonegap">open-source</a>, it was easy to spot where to jump into the code. I hacked in a screenshot function in another hour, spent another half hour making it better and another making it simpler. Just to complete the cycle, I have now wrapped up all my code into a plugin and removed my hacking from the core. Hmmm... that all seemed eerily familiar.</p>
<p>That's not to say PhoneGap is perfect. All the benefits of a completely open-source project referred to previously also come with all the drawbacks. The current version (0.9.0) is fiendishly difficult to download and get started with. It has been split into one parent project and several child projects (one per mobile platform) and it's no longer obvious what you do. It's easy enough if you're already set up but actually getting there is tricky. The most common failing of any open-source project is also true: poor documentation. There's a wiki but it's mostly out-of-date. There's a section on phonegap.com called 'docs' but they're also out-of-date. There's an API reference but it's autogenerated from comments and is also out-of-date. The only place to get accurate information is the Google group but that's not documentation, that's solutions to problems.</p>
<p>There have also been some claims that PhoneGap is unstable and crashes but personally, I haven't seen that. It's possible that the crashes and performance issues are the result of memory leaks in the JavaScript. Appcelerator automatically runs <a href="http://www.jslint.com/">JSLint</a> on your code before compilation so it will highlight any problems. If you can fit that into your standard workflow, you might be able to avoid some of the instability.</p>

<h2>Additional comments</h2>

<p>It seems that <a href="http://disqus.com">Disqus</a> (the commenting system I'm using below) has some problems with Safari 5 & Chrome so this comment was sent via <a href="http://gist.github.com/">gist</a> (I knew I shouldn't have stopped using <a href="http://blah.thingsinjars.com/post/180/noodle/" title="Noodle">Noodle</a>).</p>
<p>I'll respond later. I've just got back from the Apple store and have toys to play with.</p>


<p><em>Comment from Jeff Haynie (<a href="http://twitter.com/jhaynie">@jhaynie</a>)</em></p>
<p>A few comments about Appcelerator.</p>
<p>1. We're completely open source and you can see all our active development every single commit on github.com/appcelerator.  We have plenty of outside core open source contributors.</p>
<p>2. Yeah, to do what we're doing, it's complicated - much more than Phonegap - so it does mean with complexity it's hard to grok.  however, the source is all there. Also, it's full extensible through our SDKs and we this SDK as the way we build Titanium itself.</p>
<p>3. For Desktop, we _only_ upload to our build servers as a convenience to cross-platform packaging.  Nothing mysterious and all the scripts we run are included (and open source) so you can run them on your own. Plenty of our customers do this behind the firewall.  When you're developing locally (say on a OSX machine), it's all local during dev. Only cross-platform packaging is done as a convenience to developers.  We have to pay for this bandwidth and storage and we do it to make it easier.  And it's free.</p>
<p>Hope this clarifies some of the above.   Phonegap's a great project and we love the team - but I think we're trying to do different things and come at it from different approaches. In the end, this is good for developers as it gives everyone more choice based on their needs.</p>      </div>
]]></description>
<pubDate>Thu, 17 Jun 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>licences.xml</title>
<link>http://thingsinjars.com/post/290/licencesxml/</link>
<guid>http://thingsinjars.com/post/290/licencesxml/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-290">
        <p><a href="http://thingsinjars.com/post/290/licencesxml/">licences.xml</a></p>
<p>JavaScript libraries and CSS frameworks are very popular these days. With each library, plugin, extension and template, comes another licencing statement. For most of these licences (<a href="http://www.opensource.org/licenses/mit-license.php">MIT</a>, for instance), you must include the licence statement in order to be able to use the code. In many cases, you also have to provide the original source and your own modifications. While, for uncompiled technologies such as these, this is a trivial matter, both this requirement and that of including the licence are awkward to implement if you like to minify your code. The licence is usually kept in an uncompressed comment at the top of the library (the YUI compressor specifically takes this into account with comments marked /*!  */ ) and, although anyone can read your modifications to whatever you've used, post-minification code is much harder to follow (cf. three of my last four blog posts) and is really not 'in the spirit' of sharing your code.</p>
<p>I'd like to be able to bundle all the licences and sources together outside the production files. Somewhere the interested user would be able to look them up if they liked but not somewhere that would automatically be downloaded on a standard visit. To that end, I have looked around for an established standard for this and not found anything. If you know of one, please let me know. Until I do find a good standard, here's my suggestion – a simple XML file located at /licences.xml in the format outlined below. It contains details of the file the licence pertains to, the uncompressed source (optional), the title of the licence and a URL where the full licence text can be found (on opensource.org or creativecommons.org, for instance). It also includes a (probably superfluous) shortname for the licence. I might remove that bit. You can optionally include this meta in your HTML if you want an explicit link between your source and the licence file:</p>
<pre><code>&lt;meta name=&quot;licences&quot; value=&quot;/licences.xml&quot; /&gt;</code></pre> 
<p>I'm currently undecided as to whether to go with XML or JSON. They're fairly interchangeable (barring XML attributes) but JSON takes less space. Then again, there's not as much need to save space in this file. Anyone have any recommendations? The entire format is, of course, up for discussion. Have I forgotten anything? Have I included anything unnecessary? I'm going to start using this in my projects until someone points out some major legal problem with it, I think.</p>
 
<h2>XML</h2> 
<pre> 
&lt;licences&gt;
 &lt;licence&gt;
  &lt;source&gt;
   &lt;url&gt;
    /includes/script/jquery/1.4/jquery.min.js
   &lt;/url&gt;
   &lt;uncompressed&gt;
    /includes/script/jquery/1.4/jquery.js
   &lt;/uncompressed&gt;
  &lt;/source&gt;
  &lt;deed&gt;
   &lt;title&gt;
   MIT License
   &lt;/title&gt;
   &lt;url&gt;
    http://www.opensource.org/licenses/mit-license.php
   &lt;/url&gt;
   &lt;shortform&gt;
   MIT
   &lt;/shortform&gt;
  &lt;/deed&gt;
 &lt;/licence&gt;
 &lt;licence&gt;
  &lt;source&gt;
   &lt;url&gt;
    /includes/script/custom/0.1/custom.js
   &lt;/url&gt;
   &lt;uncompressed&gt;
    /includes/script/custom/0.1/custom.min.js
   &lt;/uncompressed&gt;
  &lt;/source&gt;
  &lt;deed&gt;
   &lt;title&gt;
   Attribution Share Alike
   &lt;/title&gt;
   &lt;url&gt;
    http://creativecommons.org/licenses/by-sa/3.0
   &lt;/url&gt;
   &lt;shortform&gt;
   cc by-sa
   &lt;/shortform&gt;
  &lt;/deed&gt;
 &lt;/licence&gt;
&lt;/licences&gt;
</pre> 
<h2>JSON</h2> 
<pre> 
{
 licences:{
  {
   source:{
    url:'/includes/script/jquery/1.4/jquery.min.js',
    uncompressed:'/includes/script/jquery/1.4/jquery.js'
   },
   deed:{
    title:'MIT License',
    url:'http://www.opensource.org/licenses/mit-license.php',
    shortform:'MIT'
   }
  },
  {
   source:{
    url:'/includes/script/custom/0.1/custom.min.js',
    uncompressed:'/includes/script/custom/0.1/custom.js'
   },
   deed:{
    title:'Attribution Share Alike',
    url:'http://creativecommons.org/licenses/by-sa/3.0',
    shortform:'cc by-sa'
   }
  }
 }
}
</pre>      </div>
]]></description>
<pubDate>Fri, 20 Aug 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>List of Touch UI gestures</title>
<link>http://thingsinjars.com/post/289/list-of-touch-ui-gestures/</link>
<guid>http://thingsinjars.com/post/289/list-of-touch-ui-gestures/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-289">
        <p><a href="http://thingsinjars.com/post/289/list-of-touch-ui-gestures/">List of Touch UI gestures</a></p>
<p>Just now, I'm trying to improve the UI for the <a href="http://www.angryrobotzombie.com">Factory's</a> first <a href="http://itunes.apple.com/uk/app/harmonious/id363375481" title="harmonious. for iPhone, iPod touch, and iPad on the iTunes App Store">iPhone app</a>. While doing this, I've come up with a list of available areas and gestures in a touch-driven app that you can use for actions. I thought I'd put them here so other people could point out where I've gone wrong and what I've forgotten:</p>
<ul>
  <li>Menus
    <ul>
      <li>Permanent on-screen menu</li>
      <li>Transient on-screen menu (requires trigger)</li>
      <li>Different screen menu (any number of them, requires trigger)</li>
    </ul>
  </li>
  <li>Static (can be overloaded with function based on position)
    <ul>
      <li>Single-tap
        <ul>
        <li>Single-tap 1 touch</li>
        <li>Single-tap 2 touches</li>
        <li>Single-tap 3 touches</li>
        </ul>
      </li>
      <li>Double-tap
        <ul>
          <li>Double-tap 1 touch</li>
          <li>Double-tap 2 touches</li>
          <li>Double-tap 3 touches</li>
        </ul>
      </li>
      <li>Touch and Hold
        <ul>
          <li>Touch and Hold 1 touch</li>
          <li>Touch and Hold 2 touches</li>
          <li>Touch and Hold 3 touches</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Dynamic (Gestures)
    <ul>
      <li>Touch and Move 1 touch
        <ul>
          <li>Up</li>
          <li>Down</li>
          <li>Left</li>
          <li>Right</li>
        </ul>
      </li>
      <li>Touch and Move 2 touches
        <ul>
          <li>Up</li>
          <li>Down</li>
          <li>Left</li>
          <li>Right</li>
          <li>Apart (Zoom)</li>
          <li>Together (Pinch)</li>
          <li>Rotate clockwise</li>
          <li>Rotate anticlockwise</li>
        </ul>
      </li>
      <li>Touch and Move 3 touches
        <ul>
          <li>Up (Swipe)</li>
          <li>Down (Swipe)</li>
          <li>Left (Swipe)</li>
          <li>Right (Swipe)</li>
          <li>Apart (Spread)</li>
          <li>Together (Gather)</li>
          <li>Rotate clockwise</li>
          <li>Rotate anticlockwise</li>
        </ul>
      </li>
    </ul>      
  </li>
</ul>      </div>
]]></description>
<pubDate>Sat, 10 Apr 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Scene and Herd archive</title>
<link>http://thingsinjars.com/post/288/scene-and-herd-archive/</link>
<guid>http://thingsinjars.com/post/288/scene-and-herd-archive/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-288">
        <p><a href="http://thingsinjars.com/post/288/scene-and-herd-archive/">Scene and Herd archive</a></p>
Continuing the webcomic theme from yesterday, I finally uploaded the archive of strips from the webcomic I used to do in 2003.

It actually started off as a cartoon on flyers advertising Baby Tiger gigs before developing into music reviews for a while before ending up in the final version.

Start at the <a href="http://thingsinjars.com/cartoons/last/">far end of the cartoon department</a>, third floor.      </div>
]]></description>
<pubDate>Wed, 10 Mar 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Rules: The Comic</title>
<link>http://thingsinjars.com/post/266/rules-the-comic/</link>
<guid>http://thingsinjars.com/post/266/rules-the-comic/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-266">
        <p><a href="http://thingsinjars.com/post/266/rules-the-comic/">Rules: The Comic</a></p>
I found some old sketches at the weekend and decided that I shouldn't just leave them in a drawer doing nothing.

I, therefore, present to you:

<a href="http://blah.thingsinjars.com/widgets/rules/index.html">The Rules</a>

It's kind of a web comic but it only has 19 issues, no plot and won't be continuing.      </div>
]]></description>
<pubDate>Tue, 09 Mar 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>The Shadow Government and a Hyperbagel</title>
<link>http://thingsinjars.com/post/265/the-shadow-government-and-a-hyperbagel/</link>
<guid>http://thingsinjars.com/post/265/the-shadow-government-and-a-hyperbagel/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-265">
        <p><a href="http://thingsinjars.com/post/265/the-shadow-government-and-a-hyperbagel/">The Shadow Government and a Hyperbagel</a></p>
<p>I <a href="http://blah.thingsinjars.com/post/262/synchronised-podcasts/">listen to a bunch of podcasts</a>. I watch the Daily Show and the Colbert Report. I <a href="http://www.last.fm/user/thingsinjars">listen to a lot</a> of They Might Be Giants. When you combine this with the audiobooks I listen to, the <a href="http://www.twitpic.com/ewagy">shows I go to</a> and the paper books I read, you start to spot a pattern. A slightly sinister pattern...</p>
<ul class="gallery">
<li>
<a href="http://thingsinjars.com/uploaded/images/expanded/theshadowgovernment.png" rel="lightbox[265]" title="The Illiternati"><img src="http://thingsinjars.com/uploaded/images/thumbs/theshadowgovernment.png" alt="The Illiternati" /></a></li>
</ul>
<p>This originally started as a connectivity diagram of American Literary Non-fictionists but after I'd finished I realised it's not entirely American, it's not entirely non-fictionists. It's not entirely comedy and not entirely literary. After showing it to a friend though, he immediately suggested 'The New Illuminati' or possibly the Literary Illuminati. Maybe just the Illiternati. Any way round you have it, John Hodgman appears to be as some kind of Literpope in the middle of a literspiracy.</p>
<p>From what I can figure, I need to write some world economics exposé with Planet Money, discuss the software I used to analyse the markets with This Week in Tech and appear onstage at The Moth to tell the audience how the experience changed my life then I can join the dots on the diagram and reveal the secret Iliternati symbol. I think it'll be somewhere between the <a href="http://en.wikipedia.org/wiki/File:Peace_symbol.svg">CND logo</a> and a hyperbagel.</p>      </div>
]]></description>
<pubDate>Mon, 08 Mar 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Some kind of monster</title>
<link>http://thingsinjars.com/post/263/some-kind-of-monster/</link>
<guid>http://thingsinjars.com/post/263/some-kind-of-monster/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-263">
        <p><a href="http://thingsinjars.com/post/263/some-kind-of-monster/">Some kind of monster</a></p>
I've been trying to make myself sketch a lot more recently. This was mostly prompted by my decision to start up <a href="http://www.angryrobotzombie.com/">The Angry Robot Zombie Factory</a> as an actual company doing web development and illustration.

I've been keeping an <em>almost</em> daily sketch blog over on <a href="http://thingsinjars.tumblr.com/">tumblr</a> and promoting any good pieces over onto my actual <a href="http://permanentpencil.com">illustration portfolio</a>. At some point, I'll bring all these different sites and things together. Until then, here's a sketch of a few things from the last couple of weeks.      </div>
]]></description>
<pubDate>Thu, 04 Mar 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Synchronised Podcasts</title>
<link>http://thingsinjars.com/post/262/synchronised-podcasts/</link>
<guid>http://thingsinjars.com/post/262/synchronised-podcasts/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-262">
        <p><a href="http://thingsinjars.com/post/262/synchronised-podcasts/">Synchronised Podcasts</a></p>
<p>This must exist somewhere. I just can't find it.</p>
<p>I listen to a lot of podcasts in a week and I use quite a few different computers. One desktop at home, one laptop while out and about and a PC and an iMac at work. I want some service (or combination of web service and application) that I can use to manage my podcast subscriptions regarless of where I am.</p>
<p>At the moment, I have iTunes installed on my desktop, my laptop and the iMac at work and I have subscribed to my collection of podcasts in each of them. I want to be able to plug in my iPod and have it delete the podcasts I've listened to and get the latest episodes of each of my subscriptions. At the moment, I plug it into the desktop, copy on the latest 'Planet Money' and listen. A couple of days later, there's another episode released so I plug into my laptop and it offers the episode I've just finished listening to and the new one. A few days later, I'm working on the office iMac and plug in my iPod, it suggests the last weeks-worth of episodes. I have to manually go into every subscription and drag over the individual files that I want to listen to.</p>

<p>This is, of course, ignoring my usual niggle about iTunes which is its insistence on pausing downloads with the message "iTunes has stopped updating this podcast because you have not listened to any episodes recently". No, keep downloading, iTunes. I didn't tell you to stop.</p>

<p>What I'd like to have is a web site where I can put in my podcast subscriptions and it will track the latest episodes of each. I can then either point iTunes to this site so that I can point all my installations at it or it will provide an application which can be used to put the latest episodes onto my iPod. When I plug in my iPod, the application tells the site which ones I've listened to and it removes them from my listening queue. The application could, also be stored on the iPod itself to enable it to be used wherever the iPod is plugged in, not just on computers with iTunes.</p>
<p>Am I explaining myself clearly enough? It just seems so simple, it should already exists within iTunes. It is entirely possible that Apple's recent acquisition of <a href="http://lala.com">Lala</a> could be the first step in an online iTunes which would solve these problems. If anyone has any suggestions for the best way to achieve this, please let me know. I thought of a way of doing it with <a href="http://dropbox.com">Dropbox</a> but it would only work if the music bit of my iTunes library weren't bigger than my Dropbox account.</p>      </div>
]]></description>
<pubDate>Fri, 26 Feb 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Still Life Under Ice</title>
<link>http://thingsinjars.com/post/261/still-life-under-ice/</link>
<guid>http://thingsinjars.com/post/261/still-life-under-ice/</guid>
<description><![CDATA[
        <div class="teaser flickr" id="teaser-261">
        <p><a href="http://thingsinjars.com/post/261/still-life-under-ice/">Still Life Under Ice</a></p>
<p><a href="http://farm3.static.flickr.com/2528/4053678593_65aacdba4a.jpg"  rel="lightbox[{smod:id}]"  title="Still Life Under Ice"><img src="http://farm3.static.flickr.com/2528/4053678593_65aacdba4a_m.jpg" alt="Still Life Under Ice"/></a>I like the textures in this one but I might prefer it black & white. Hmmm.. undecided.</p>
<p>Originally uploaded by <a href="http://www.flickr.com/photos/thingsinjars/4053678593/">thingsinjars</a> on <a href="http://www.flickr.com">flickr</a></p>      </div>
]]></description>
<pubDate>Tue, 26 Jan 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Appreciate the artisans</title>
<link>http://thingsinjars.com/post/259/appreciate-the-artisans/</link>
<guid>http://thingsinjars.com/post/259/appreciate-the-artisans/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-259">
        <p><a href="http://thingsinjars.com/post/259/appreciate-the-artisans/">Appreciate the artisans</a></p>
I know that every professional thinks their bit of the process is more important than people give them credit for. Designer's don't just colour in wireframes handed to them by the Information Architect. IAs don't just draw boxes and arrows. Copy writers don't just copy-and-paste the company brochure over the lorem ipsum.

Now that I've said that, I must now point out: Developers don't get nearly enough credit.

This may be something to do with the odd confusion that is 'web designer vs. web developer'. In some - and possibly the majority of - agencies, the web <em>designer</em> not only designs what the page looks like in Photoshop/Fireworks/Whatever but also produces the HTML templates, CSS and whatever JavaScript they feel comfortable with (the tutorials at <a href="http://jqueryfordesigners.com/">jQuery for Designers</a> probably help, too). In these agencies, if there is such a person as a web <em>developer</em>, they are most likely responsible for moving the relevant bits of HTML into template files, adding in any back-end integration and possibly writing some of the trickier JavaScript. The confusion arises in the other kind of agencies. The kind where web <em>designers</em> make Photoshop files and web <em>developers</em> turn them into HTML. The designer doesn't necessarily need to know anything about HTML, semantics or scripting. Not to minimise the importance of this kind of designer - they'll know a lot about typography, and visual relations, probably quite a lot about user experience and the process involved in bridging the gap between what the client wants to say and how the user wants to hear - but it's this kind of web developer I think doesn't get enough credit. 

If you're designing a site with a full knowledge of how it could be marked up, you will naturally - even if it's subconsciously - be marking it up in your head. This will influence your design and not necessarily in a bad way. You might ensure the semantics are just that little bit clearer or you might nudge these bits over that way so they can be grouped with those other ones there. If, however, you design with no thought at all about how this is going to be made, you will, most likely, do some things that you wouldn't otherwise. If your front-end developer can take this and turn it into a perfectly semantic, clean-coded masterpiece of HTML and CSS then apply JavaScript to progressively enhance the heck out of it and still keep it looking like you designed, they deserve to be lauded, applauded, praised and thanked. Publicly. The usual outcome of this situation is that the designer gets asked along to the awards ceremonies, puts it on their portfolio, an article in <a href="http://www.thedrum.co.uk/">the Drum</a>, happy. The developer gets a pat on the back from the team leader and asked if they could just tidy up how it looks in IE5.5 before they head home for the night, that'd be great, thanks.

Sure, maybe we just need some better awards ceremonies for geeks. The kind of thing that the agency sales team will be able to brag about to potential customers (as that, in essence, seems to be the point of awards ceremonies) but I also think there might need to be a bit of a change of opinion in the industry. Just as designers don't just colour in wireframes, developers don't just open the designs in Photoshop and press 'Save for web...'.

I hope this doesn't sound too ranty. These thoughts were prompted after seeing a few designer and copy writer portfolios which contained sites that either I'd built or one of my team had built. Writers credited, designers credited, developers (who built some awesome stuff on them, by the way) lost in the mists of time.      </div>
]]></description>
<pubDate>Mon, 25 Jan 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Heidi</title>
<link>http://thingsinjars.com/post/258/heidi/</link>
<guid>http://thingsinjars.com/post/258/heidi/</guid>
<description><![CDATA[
        <div class="teaser audio" id="teaser-258">
        <p><a href="http://thingsinjars.com/post/258/heidi/">Heidi</a></p>
This probably won't mean much to anyone unless you're familiar with the <a href="http://en.wikipedia.org/wiki/Heidi,_Girl_of_the_Alps">Japanese Heidi cartoon</a> which was popular in Germany in the 80s.

 

When I first heard the theme, I thought <a href="http://www.youtube.com/watch?v=jjn2xAfOfzo">the intro</a> should have gone like this.      </div>
]]></description>
<pubDate>Fri, 22 Jan 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>User style</title>
<link>http://thingsinjars.com/post/256/user-style/</link>
<guid>http://thingsinjars.com/post/256/user-style/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-256">
        <p><a href="http://thingsinjars.com/post/256/user-style/">User style</a></p>
<p>A few years ago, I made a prediction about the way the web was going and so far it hasn't come true but it's definitely coming closer. To me it seems that the logical extension of us developers separating style and substance – what we've been doing for years with semantic mark-up – is for the general consumer to take that substance and give it their own style. I'm in no way suggesting that everyone become a designer. That would be a terrible, terrible thing. What I mean is that the consumer takes in/reads/experiences whatever it is you're giving to them in the manner that best suits them. There are many examples of what I mean around already but they're still not quite where I think they will end up.</p>

<h2>RSS</h2>
<p>We (web developers) already provide RSS feeds on our sites. By subscribing to a site's RSS feed, you get the content delivered directly to your RSS reader. As long as the site is providing the full article content (shame on you, if not) the consumer gets to see your content in a design format you have little control over. There is a basic level allowed for RSS formatting but nothing you can rely on. The control for the visual appearance of your content is now in the hands of the designer of the reader and the consumer (by way of choosing which reader they use).</p>

<h2>userstyle.css</h2>
<p>This was what initially prompted my thoughts on the subject. I've used Opera as my main browser for almost 10 years and I've always liked the Author mode/User mode switch. In essence, you can quickly toggle between seeing a web page as it was intended by the designer or disregarding the original layout and applying your own stylesheets to it. For the most part, this is used to be able to set high contrast for visually impaired users or to test various criteria (showing only images that have missing alt attributes, for example) but they can be used to produce any visual effect achievable with CSS.</p>

<p>User stylesheets can also be assigned on a per-site basis rather than globally which means that you could have your Google results rendered in courier, right-aligned in green on black while your facebook pages can be set in Times in a sepia colourscheme.</p>

<p>As with many things on the web, userstyles became a lot more popular once this functionality was available in Firefox (via the add-on <a href="https://addons.mozilla.org/en-US/firefox/addon/2108">Stylish</a>) and not just Opera. Now there's a growing <a href="http://userstyles.org/">community of Userstyle developers</a> and a <a href="http://userstyles.org/styles/browse?sort=popularity&sort_direction=desc">directory of styles</a>. Unfortunately, this is still not quite ready for mainstream use. It requires at least a basic level of technical ability to enable userstyles and to install them.</p>

<h2>userscript.js</h2>
<p>The userstyles community is, however, dwarfed in comparison to the userscript community. In pretty much exactly the same way that userstyles work, users can execute a specific Javascript file whenever they visit a site. Again, this can be enabled in Opera using site preferences and in Firefox using the <a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey add-on</a>. These scripts can completely change the way a site functions as well as how it looks. Combine them with userstyles (which userscripts can include automatically) and the only thing you can rely on remaining from your original design is the URL. There's a <a href="http://userscripts.org/">massive database of userscripts</a> available.</p>

<p>Again, though, these are still just that <em>little bit too hard</em>. The standard user isn't going to install the extension, isn't going to browse for scripts and isn't going to run Opera so these are still a bit too far away.</p>

<h2>Grab now, read later</h2>
<p>There are now quite a few sites where you can save stuff to read later. If you find an interesting article or a funny blog post but don't have time to read it or if it appears on a site with a garish and unusable design, you can send it to <a href="http://www.instapaper.com/">Instapaper</a> or <a href="http://www.evernote.com/">Evernote </a>. You can then read it in their interface, on your iPhone, on your Kindle... all separated from your design.</p>

<p>It's not only text that gets this treatment, you can use <a href="http://emberapp.com/">Ember</a> and <a href="http://www.realmacsoftware.com/littlesnapper/">LittleSnapper</a> to grab and store visuals for later perusal or use <a href="http://huffduffer.com/">Huffduffer</a> to collect any audio files you find and serve them back to you as your very own personalised podcast. Again, this is <em>your</em> content separated entirely from the way you wanted it seen. And that's a good thing.</p>

<p>For content creators, all this means is that your content can be consumed anywhere, even via sites, tools and delivery mechnisms you've never heard of. Designers, don't despair, users aren't suddenly going to take their content elsewhere and not need you any more – users still want and <em>need</em> things designed well, this just means that if your design works for the user for a particular type of content, they'll use it for any content of that type. I'd much rather watch youtube videos using vimeo's layout than youtube's. Actually, I'd much rather have vimeo's comments, too.</p>

<p>We're still quite a way off the average user being able to see whatever they want however they want it but these technologies and tools are definitely heading that way. I just wish I'd made a bet on it way back when.</p>      </div>
]]></description>
<pubDate>Fri, 15 Jan 2010 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Crowdsourced Weather - Part 2</title>
<link>http://thingsinjars.com/post/255/crowdsourced-weather---part-2/</link>
<guid>http://thingsinjars.com/post/255/crowdsourced-weather---part-2/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-255">
        <p><a href="http://thingsinjars.com/post/255/crowdsourced-weather---part-2/">Crowdsourced Weather - Part 2</a></p>
<p>So, I couldn't help myself. I had a niggling idea at the back of my head that I needed to get out. After coming up with this <a href="http://blah.thingsinjars.com/post/254/crowdsourced-weather/">Twitter weather</a> idea last week, I decided to spend a couple of hours this weekend building it. As if I didn't have other things I should have been doing instead...</p>

<p>It works pretty much exactly how the pseudocode I mentioned last time describes. Every few minutes, a script will search Twitter for mentions of any weather words from several different languages. It will then look up the location of the person who tweeted that and store it. Single reports might be wrong and users might not have stored their actual location but over a large enough sample, this system becomes more accurate. The script removes any matching twets older than 6 hours.</p>

<p>To display, I actually ended up using <a href="http://en.wikipedia.org/wiki/Geohash">Geohashes</a> instead of <a href="http://www.geotude.com/">Geotudes</a> because it is easier to simplify them when you zoom out just by cutting off the tail of the hash. For example, the physical area denoted by gcvwr3qvmh8vn (the geohash for Edinburgh) is contained within gcvwr3 which is itself contained within gcv. There are a few <a href="http://en.wikipedia.org/wiki/Geohash#Limitations">technical problems with geohashes</a> but it seems the best fit for this purpose. If anyone knows of any better suggestion, please let  me know. I do realise that this is quite possibly the slowest, most inefficient JavaScript I've ever written because it makes an AJAX call for every <a href="http://wiki.xkcd.com/geohashing/Graticule">graticule</a> and it probably should just send the South-East and North-West bounds and get back an array of them but, like I said, there were other things I should have been doing. Because the overlaid grid changes resolution based on zoom level, there are a few places where it is either tragically slow (resolution too fine) or terribly inaccurate (resolution too rough). That's just a case of tweaking the algorithm. Similarly, it's set to display reports of weather if there are 2 or more matches but it could be tweaked to only show if a larger number have reported something.</p>

<p>So go, play with the <a href="http://blah.thingsinjars.com/widgets/weather/index.html">Twitter-generated weather map</a>. If someone can come up with a good, catchy name, or some better graphics, that'd be great, thanks.</p>


<p>Source code is available: <a href="http://thingsinjars.com/uploaded/other/twitter-weather-1.0.zip">twitter-weather-1.0.zip [Zip - 298KB]</a>.</p>
<p>You'll need your own Twitter login and database account to use it.</p>
      </div>
]]></description>
<pubDate>Mon, 21 Dec 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Crowdsourced Weather</title>
<link>http://thingsinjars.com/post/254/crowdsourced-weather/</link>
<guid>http://thingsinjars.com/post/254/crowdsourced-weather/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-254">
        <p><a href="http://thingsinjars.com/post/254/crowdsourced-weather/">Crowdsourced Weather</a></p>
<p>This is a more general version of the <a href="http://uksnow.benmarsh.co.uk/">#uksnow map</a> idea. It's a crowd-sourced weather map which relies on the fact that any one individual tweet about the weather might be inaccurate but given a large enough sample, enough people will mention the weather in their area to make this a workable idea. It doesn't require people to tweet in a particular format.</p>

<h2>To get info</h2>

<pre>
Have an array of weather words in various languages (rain, hail, snow, schnee, ame, yuki)
every 5 minutes:
	foreach weatherword
		search twitter for that word
			http://search.twitter.com/search.atom?q=rain
		retrieve latest 100 tweets
		foreach
			get user info
				http://twitter.com/users/show.xml?screen_name=username
			get user.location if available
			geocode
			save:
				username, time, lat, long, <a href="http://www.geotude.com/">geotude</a>, weatherword
		Remove any tweets about this weatherword older than 6 hours.
			
</pre>

<h2>To display info</h2>
<pre>
Show a Google map
Based on current Zoom level, split the current map into about 100 geotudes
foreach geotude
	search database for any weather results for that block (probably using an ilike "1234%" on the geotude field)
	sort by weatherword count descending
	draw an icon on top of that block to show the most common weatherword
	
If the user zooms in, recalculate geotudes and repeat.
</pre>

<p>I quite like that this uses <a href="http://www.geotude.com/">geotudes</a> which I think are an excellent idea.</p>

<p>I built a <a href="http://blah.thingsinjars.com/widgets/weather/">very basic version of this</a>. Read more about it in <a href="http://blah.thingsinjars.com/post/255/crowdsourced-weather---part-2/">Part 2</a>.</p>
      </div>
]]></description>
<pubDate>Thu, 17 Dec 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>What's your Google Suggest number?</title>
<link>http://thingsinjars.com/post/253/whats-your-google-suggest-number/</link>
<guid>http://thingsinjars.com/post/253/whats-your-google-suggest-number/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-253">
        <p><a href="http://thingsinjars.com/post/253/whats-your-google-suggest-number/">What's your Google Suggest number?</a></p>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/expanded/google-suggest.jpg" rel="lightbox[253]" title="What's your Google Suggest number?"><img src="http://thingsinjars.com/uploaded/images/thumbs/google-suggest.jpg" alt="What's your Google Suggest number?" /></a></li>
</ul>
<p>The next step in ego-googling: how many letters of your name do you need to type into the google search box before you are the top suggestion? The lower the better, obviously. Including spaces, My name is the top suggestion after 10 characters so I have a Google Suggest Number of 10. My <a href="http://www.flickr.com/photos/photojennic/" title="Flickr: photojennic's Photostream">darling wife</a> (who has recently changed her name) has a Google Suggest number of ∞ as she can type in her whole name and Google doesn't suggest her.</p>

<p>Turns out <a href="http://www.jerrykindall.com/2004/12/10_google_suggest_number.asp">somebody proposed this</a> first over 5 years ago. Oh well. Nothing's new on the internet.</p>      </div>
]]></description>
<pubDate>Mon, 14 Dec 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Side Tab</title>
<link>http://thingsinjars.com/post/252/side-tab/</link>
<guid>http://thingsinjars.com/post/252/side-tab/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-252">
        <p><a href="http://thingsinjars.com/post/252/side-tab/">Side Tab</a></p>
<ul class="gallery"><li><a href="http://blah.thingsinjars.com/uploaded/images/expanded/side-tab.jpg" title="Opera with Tabs down the side" rel="lightbox[252]"><img src="http://blah.thingsinjars.com/uploaded/images/thumbs/side-tab.jpg" alt="thumb of my Opera layout"/></a></li></ul>
<p>After reading Aza Raskin's post about Firefox moving its tabs <a href="http://www.azarask.in/blog/post/firefoxnext-tabs-on-the-side/">down the side</a> of the window, I decided to give it a go in Opera. It turns out to be very useful when you have a widescreen monitor. I usually end up with several dozen tabs open at once and it's much easier to be able to put them down the side in an area which is, for most websites at least, dead space. On the rare occasions I do find myself on a website which requires more than the 1470px horizontal space this gives me, I can just tap f4 and get my full 1650px back. As the window sidepanel also groups by window and lists all tabs open across all windows, I can keep them ordered thematically, too.</p>
<p>This arrangement definitely doesn't work, however, when you have a small screen. When I tried this on my netbook, I had to choose between losing half of my screen to the tab list or only being able to read the beginning of each page title, even if I only had one tab open.</p>
<p>A quick aside, when I first read about moving tabs down the side, my initial thought was "It's a shame Opera doesn't have add-ons, I'd like to give this a go" and very nearly fired up Firefox before I realised that Opera already has this functionality and has had since (approximately) version 5 (almost 10 years ago). Just sayin'.</p>      </div>
]]></description>
<pubDate>Thu, 10 Dec 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Some simple tips</title>
<link>http://thingsinjars.com/post/251/some-simple-tips/</link>
<guid>http://thingsinjars.com/post/251/some-simple-tips/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-251">
        <p><a href="http://thingsinjars.com/post/251/some-simple-tips/">Some simple tips</a></p>
<p><em>The views and opinions expressed within are not those of National Museums Scotland. This site is in no way affiliated with National Museums Scotland or the website <a href="http://www.nms.ac.uk/">www.nms.ac.uk</a></em></p>
<p>First of all, the disclaimer: I am not a designer. If I were to make claim to being anything creative it's an <a href="http://permanentpencil.com">illustrator</a> but there's a huge difference between the two (I've always said that an illustrator makes the thing to go on the t-shirt, the designer says <em>where</em> on the t-shirt it goes). Despite the recent trend for everyone to call themselves web designers, I'm still going to go by web developer. I make things.</p>
<p>Bearing that in mind, there are still quite a few web design and UX tips and techniques I've picked up along the way which can be applied to most sites and not interfere with the mysterious ways of designers.</p>
<p>Recently, I've been reworking templates for <a href="http://www.nms.ac.uk/">National Museums Scotland</a> for faster load times and better SEO and I'll illustrate what I'm talking about with a couple of examples from there. The brief on these templates is that the content can't really change and there are some chunks that the CMS generates which can't be changed. Note: the NMS templates are completely finished yet and those that are haven't been rolled out across the whole site but sticking with that whole <a href="http://en.wikipedia.org/wiki/Release_early,_release_often">release early, release often</a> way of doing things, these little incremental improvements can be applied without affecting too much else.</p>

<p>For reference, here are before and after screen grabs of two of the templates.</p>
<ul class="gallery">
<li><a href="http://thingsinjars.com/uploaded/images/tips-our-before.jpg" rel="lightbox[1]" title="Main Gateway before"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-our-before.jpg" alt="Our Museums Before"/></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/tips-our-after.jpg" rel="lightbox[1]" title="Main Gateway after"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-our-after.jpg" alt="Our Museums After"/></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/tips-war-before.jpg" rel="lightbox[1]" title="Museum page before"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-war-before.jpg" alt="Museum gateway before"/></a></li>
<li><a href="http://thingsinjars.com/uploaded/images/tips-war-after.jpg" rel="lightbox[1]" title="Museum page after"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-war-after.jpg" alt="Museum gateway after"/></a></li>
</ul>

<p>Some people will find these tips blatantly obvious but the fact that pages still get made without considering these means they do need reiterating.</p>

<h2>Link the Logo</h2>
<p>The web's been around for a few years now and there are a few conventions users have gotten used to. One of them is that the logo is a link that takes you back to the home page. It doesn't harm anything to have a link there so even if 99% of visitors don't use it, why annoy the 1% who do?</p>

<h2>Don't link to the search</h2>
<p>From the moment the visitor decides they want to search your site for something, the most important thing is to get the results in front of them as quickly as possible. It therefore makes for a better experience if you bring the results one step closer to them. Rather than requiring the user to click on a link to get to the search form to do their search to get the results, put the search box on every page. They fill it in and go to the results page. If the user wants to take advantage of any advanced search features you may have, they can modify their search from the results page.</p>
<p><img src="http://thingsinjars.com/uploaded/images/tips-search.jpg" alt="Search box positioned within header"/></p>

  <p>Note: the new template still contains a link to the search page due to some legacy requirements. I don't actually recommend this.</p>


<h2>Line up</h2>
<ul class="gallery">
  <li><a href="http://thingsinjars.com/uploaded/images/tips-line-a.gif" rel="lightbox[2]" title="Higglty.."><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-line-a.gif" alt="thumbnail of layout not aligned"/></a></li>
  <li><a href="http://thingsinjars.com/uploaded/images/tips-line-b.gif" rel="lightbox[2]" title="...and straight"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-line-b.gif" alt="thumbnail of layout aligned"/></a></li>
</ul>
<p>I'm sure there's more to design than this but there are a couple of well tested rules I recommend any non-designer to learn:</p>

<ol>
       <li>If it doesn't line up, make it line up.</li>
       <li>If it's already lined up, make it not.</li>
</ol>

<p>That and a subscription to iStock and you're done...</p>

  <p>Note: This was a joke, real designers please don't stab me with your crayons.</p>


<h2>Make the hit area as big as possible</h2>
<ul class="gallery">
  <li><a href="http://thingsinjars.com/uploaded/images/tips-hit-a.jpg" rel="lightbox[3]" title="Before and after close-up"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-hit-a.jpg" alt="Thumbnail of gateway panel comparison" /></a></li>
  <li><a href="http://thingsinjars.com/uploaded/images/tips-hit-b.jpg" rel="lightbox[3]" title="Blue bits are clickable"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-hit-b.jpg" alt="Thumbnail of gateway panel hit area comparison" /></a></li>
</ul>
<p>From the gateway page for <a href="http://www.nms.ac.uk/our_museums.aspx">Our Museums</a>, there are two ways the user could go. They were either looking for opening times (in which case, they're done), or they want to find out more information about the individual museums on their own pages. To that end, it makes sense to make the next step as easy as possible and bascially turn the content this page into six huge buttons. To keep everything semantic, JavaScript has been used here to extract the destinations from each of the links and apply them to the whole panel area (it'll default to linked text and image with JavaScript disabled). As you can see, doing this changes the hit area for each museum from a line of text to a veritable barn door.</p>

<h2>White text on a white background is not good</h2>
<ul class="gallery">
  <li><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-white-a.jpg" alt="white text laid over white background"/></li>
  <li><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-white-b.jpg" alt="white text laid over black background"/></li>
</ul>
<p>Actually, I'm not sure whether it's the fact that the link wasn't as readable as it could have been or the fact that to go home requires poking her in the eye that upset me most. Either way, if you do need to use an image that has a light bit underneath some light text and you can't shuffle it along like here, a quick wipe with the burn tool in Photoshop works wonders.</p>

<h2>Underline links</h2>
<p>I'm not going to get into the debate over whether or not <a href="http://www.gerrymcgovern.com/nt/2009/nt-2009-11-02-Web-links-actio n.htm">designers hate underlines</a> but for a high-traffic, public sector with an extremely varied demographic, I'd recommend using them. As <a href="http://boagworld.com/podcast/191">Paul Boag</a> mentions, what you do with your design and your solutions for various usability issues depends on the audience. A graphic designer's portfolio might very well eschew underlines when denoting links, a government site probably shouldn't. Especially when you remember that you should <a href="http://www.webaim.org/standards/508/checklist">never rely on colour alone to convey information</a>, including whether not a piece of text is a link.</p>

<h2>Titles are titles of something</h2>
<ul class="gallery">
  <li><img src="http://thingsinjars.com/uploaded/images/tips-related-a.gif" alt="titles far away from paragraph text"/></li>
  <li><img src="http://thingsinjars.com/uploaded/images/tips-related-b.gif" alt="titles near paragraph text"/></li>
</ul>
<p>If you have a title, it generally refers to the thing below it, not the thing above it. Make sure you keep titles and the things they are titles of together.</p>

<h2>Avoid disparate navigation</h2>
<ul class="gallery">
  <li><a href="http://thingsinjars.com/uploaded/images/tips-nav-a.gif" rel="lightbox[4]" title="Several different navigations"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-nav-a.gif" alt="navigation split over two areas"/></a></li>
  <li><a href="http://thingsinjars.com/uploaded/images/tips-nav-b.gif" rel="lightbox[4]" title="Slightly combined"><img src="http://thingsinjars.com/uploaded/images/thumbs/tips-nav-b.gif" alt="navigation combined into one area"/></a></li>
</ul>
<p>Again, another of the rules of web that has evolved over the last several years: Sections go along the top, navigation down the side. To keep consistent with the rest of the site the horizontal museum links were brought down and integrated with the rest of the navigation. This maybe isn't the most illustrative example but, basically, don't have a top nav, left nav, right nav and several others when you could have just one.</p>

<h2>Only a fraction</h2>
<p>There we are, a few handy little tips for your next build project. This hasn't gone into any issues of column width, line-height - or <a href="http://en.wikipedia.org/wiki/Leading">leading</a> (pronounced /ˈlɛdɪŋ/) as designers call it, hover states or any of the myriad other things it could, just a few of the more important and easy-to-do ones.</p>      </div>
]]></description>
<pubDate>Mon, 07 Dec 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Building an Objective-C growlView</title>
<link>http://thingsinjars.com/post/250/building-an-objective-c-growlview/</link>
<guid>http://thingsinjars.com/post/250/building-an-objective-c-growlview/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-250">
        <p><a href="http://thingsinjars.com/post/250/building-an-objective-c-growlview/">Building an Objective-C growlView</a></p>
<p><em>Wherein our intrepid hero learns some Objective-C and figures out the easy bits are actually quite hard.</em></p>

  <p>This is a little guide on how to write a growl plugin to automatically send notifications as tweets. If you just want the finished thing: <a href="http://cloud.github.com/downloads/thingsinjars/GrowlBird/GrowlBird_0.2.8.zip">GrowlBird.zip [Zip - 228KB]</a></p>
<p>A couple of days ago, I decided to give myself a little software development task to write a <a href="http://twitter.com">Twitter</a> <a href="http://growl.info">Growl</a> view. Growl is a centralised notification system for Mac OS X that lots of other applications can use so that there's one consistent way of showing notifications. </p>
<h2>Background</h2>
<p>The idea behind this little experiment wasn't to have tweets appear as growl notifications, there are already plenty of apps that do this, the idea was to have growl notifications sent to Twitter. Some friends have started organising a crowdsourced <a href="http://rotacoo.com/fridaymix/">Friday afternoon playlist</a> via <a href="http://spotify.com">Spotify</a> and I thought it'd be handy if Spotify tweeted each song as it started. The easiest way I could think of doing this was to tap into the fact that Spotify sends a Growl notification on track start and get the Growl display plugin to tweet it as well [<a href="http://thingsinjars.com/post/250/building-an-objective-c-growlview/#note-already">1</a>]. </p>
<h2>Build</h2>
<p>I downloaded the <a href="http://growl.info/files/DisplaySample.zip">Growl Display Plugin Sample 1.2 [Zip - 186 KB]</a> from the <a href="http://growl.info/downloads_developers.php">developer downloads</a> page and the <a href="http://mattgemmell.com/2008/02/22/mgtwitterengine-twitter-from-cocoa">MGTwitterEngine</a> library. I then downloaded <a href="http://developer.apple.com/technology/xcode.html">Xcode</a> so I could do the development. I have to point out here that this was my first foray into Objective-C programming and, indeed, my first attempt at anything vaguely C-related since I wrote a command-line calculator about 12 years ago. If I do it wrong, please forgive me.</p>
<p>The first thing to do was open the sample project in Xcode, figure out what files do what, etc. There is very little documentation on how Growl views or display styles work so I pretty much just spend an hour reading all the source from top to bottom. Here's a quick summary:</p>

  Sample_Prefix.pchPre-compiled header. Stuff that's included before every pre-compiled fileGrowl/Folder containing standard Growl stuff. Don't need to touch.GrowlSampleDisplay.hHeader file, didn't need to change anythingGrowlSampleDisplay.mClass for setting up things. Again, didn't touch [<a href="http://thingsinjars.com/post/250/building-an-objective-c-growlview/#note-bugged">2</a>].GrowlSamplePrefs.hDefining default preference values and naming functions to handle them. More on this later.GrowlSamplePrefs.mThe actual functions mentioned in the previous header fileGrowlSampleWindowController.hNot doing anything visual, really so I didn't need to mess around with thisGrowlSampleWindowController.mAs aboveGrowlSampleWindowView.hDeclaring objects needed for executionGrowlSampleWindowView.mInstantiating the objects then actually using them later on.
<p>Again, I'm not used to doing this stuff so if I'm using the wrong terminology, just pretend I'm not.</p>
<p>I then dragged the MGTwitterEngine library into the project drawer, saved and built. At this point it successfully did nothing different which is what I was hoping it would do. Well, it popped up the 'This is a Preview of the Sample Display' message using the MusicVideo style which is what it does when you don't screw with it.</p>

  <h2>Testing growlView</h2>
  <p>It's not actually that easy to test growlView plugins. You can't simply add and remove them. To install, you double-click on it. You should be able to see it listed in the Display tab of the preference pane. To <em>re-install</em>, you need to delete ~/Library/Preferences/com.Growl.GrowlHelperApp, ~/Library/Application Support/Growl/Plugins/Sample.growlView and restart growl (click on the paw in the menu bar). It's a bit of a hassle.</p>

<p>The next thing was to include the MGTwitterEngine. In GrowlSampleWindowController.h, #import "MGTwitterEngine.h" and create a new object. I just followed the instructions in the <a href="http://svn.cocoasourcecode.com/MGTwitterEngine/README.txt">README</a> but be sure to follow <em>all</em> of them. If you get errors about LibXML not being installed or YAJL not working, don't worry, you just need to make sure you set USE_LIBXML to 0 in all the places you're supposed to. GrowlSampleWindowController.h now contains this:</p>
<pre><code class="prettyprint">
#import "GrowlDisplayWindowController.h"
#import "MGTwitterEngine.h"

@class GrowlBirdWindowView;

@interface GrowlBirdWindowController : GrowlDisplayWindowController {
	CGFloat						frameHeight;
	NSInteger					priority;
	NSPoint						frameOrigin;
	MGTwitterEngine *twitterEngine;
}
@end</code></pre>
<p>In GrowlSampleWindowController.m, I then instantiated the new object:</p>
<pre><code class="prettyprint">
  @implementation GrowlBirdWindowController
  - (id) init {
  	  :
  	  :
      twitterEngine = [[MGTwitterEngine alloc] initWithDelegate:self];
	    [twitterEngine setUsername:@"growlbirdtest" password:@"testgrowlbird"];
	  }
	  :</code></pre>
<p>And then modified the setNotification function to also send an update:</p>
<pre><code class="prettyprint">
- (void) setNotification: (GrowlApplicationNotification *) theNotification {
    :
	[view setTitle:title];
	[view setText:text];
  NSLog(@"sendUpdate: connectionIdentifier = %@", [twitterEngine sendUpdate:[NSString stringWithFormat:@"%@, %@", title, text]]); // The new line
  :
  }</code></pre>
<p>That was enough to get growl to send messages to appear on http://twitter.com/growlbirdtest but it doesn't make it that useful for anybody else, to be honest. The next thing to figure out was the preferences. </p>
<h2>Preferences</h2>
<p>Without documentation, this took a bit longer that I expected. To start off changing the english version before worrying about localization, find the GrowlBirdPrefs.xib in resources/en.lproj/ and open it. Interface Builder will launch then you can double-click on 'Window' and see the layout of the preference pane. Search in the Library for 'text' and drag a text field into the window then spend about half and hour clicking round the interface. Open up the various inspectors (right-click on an object), look through the different tabs, click between the newly added text field and the sliders and drop-downs that are already there just to see what's different. Once I was a bit familiar, I opened the connections tab so that I could bind the value of the text field to the value 'twitterUsername' in my code. I checked 'value', Bind to 'File's Owner' and entered 'twitterUsername' in Model Key Path. I then repeated this for twitterPassword using a Secure Text Field from the Library. The option nextKeyView is used to say which item is tabbed to next when you're navigating with the keyboard so to keep things tidy, I dragged lines from nextKeyView from each of them to the right places in the layout.</p>
<p>Back in the code, I added new default preferences in GrowlSamplePrefs.h:</p>
<pre><code class="prettyprint">
  #define Sample_USERNAME_PREF		@"Username"
  #define Sample_DEFAULT_USERNAME		@"growlbirdtest"

  #define Sample_PASSWORD_PREF		@"Password"
  #define Sample_DEFAULT_PASSWORD		@"testgrowlbird"
  :
  :
  @interface GrowlBirdPrefs : NSPreferencePane {
  	IBOutlet NSSlider *slider_opacity;
  	IBOutlet NSString *twitterUsername;
  	IBOutlet NSString *twitterPassword;
  }</code></pre>
<p>and named some handlers for them:</p>
<pre><code class="prettyprint">
  - (NSString *) twitterUsername;
  - (void) setTwitterUsername:(NSString *)value;
  - (NSString *) twitterPassword;
  - (void) setTwitterPassword:(NSString *)value;</code></pre>
<p>Be careful here, I got confused and didn't have the same spelling here for twitterUsername and twitterPassword as I had put in the interface builder as I hadn't realised the two were directly connected. They are. Obviously. The next thing to do is to write the code for these handlers:</p>
<pre><code class="prettyprint">
  - (NSString *) twitterUsername {
  	NSString *value = nil;
  	READ_GROWL_PREF_VALUE(Sample_USERNAME_PREF, SamplePrefDomain, NSString *, &value);
  	return value;
  }
  - (void) setTwitterUsername:(NSString *)value {
  	WRITE_GROWL_PREF_VALUE(Sample_USERNAME_PREF, value, SamplePrefDomain);
  	UPDATE_GROWL_PREFS();
  }
  - (NSString *) twitterPassword {
  	NSString *value = nil;
  	READ_GROWL_PREF_VALUE(Sample_PASSWORD_PREF, SamplePrefDomain, NSString *, &value);
  	return value;
  }
  - (void) setTwitterPassword:(NSString *)value {
  	WRITE_GROWL_PREF_VALUE(Sample_PASSWORD_PREF, value, SamplePrefDomain);
  	UPDATE_GROWL_PREFS();
  }
</code></pre>

<p>Build and reinstall and this will now show the same preference pane as before but with two new text fields which allow you to enter your username and password. In fact, build at several stages along the way. Every time you make a change, in fact. If something breaks, check the error log to see if it's something predictable that should have broken at that point or if you've done something wrong. Also, keep the OS X log app Console open in the background. It will spew out error messages if you do something wrong. It's also good to have your code write out console messages to keep a track on what your code is doing like so:</p>
<pre><code class="prettyprint">
  - (NSString *) twitterPassword {
  	NSString *value = nil;
  	READ_GROWL_PREF_VALUE(Bird_PASSWORD_PREF, SamplePrefDomain, NSString *, &value);
  	NSLog(@"twitterPassword = %@", value);
  	return value;
  }
</code></pre>

<p>You'll notice we're still sending messages to the growlbirdtest account because, even though we are reading and saving the username and password, we're not doing anything with them. That's easily remedied by editing GrowlSampleWindowView.m again and replacing the hard-coded login details with a couple of lines to read from the preferences or fall back on the default:</p>
<pre><code class="prettyprint">
  twitterEngine = [[MGTwitterEngine alloc] initWithDelegate:self];
	NSString *twitter_username = Bird_DEFAULT_USERNAME;
	NSString *twitter_password = Bird_DEFAULT_PASSWORD;
	READ_GROWL_PREF_VALUE(Bird_USERNAME_PREF, SamplePrefDomain, NSString *, &twitter_username);
	READ_GROWL_PREF_VALUE(Bird_PASSWORD_PREF, SamplePrefDomain, NSString *, &twitter_password);
	[twitterEngine setUsername:twitter_username password:twitter_password];
	NSLog(@"Twitter Login: username = %@", twitter_username);
</code></pre>
<p>And, hooray! It works and posts to the account for which you entered details. Sort of. Some apps double-post. I haven't figured out why yet.</p>
<h2>Renaming</h2>
<p>After all that, the final bit (which I thought would be the easiest) was to rename the growlView from 'Sample' to 'Bird'. I have read that in the latest version of Xcode (which presumably comes with Snow Leopard), there's a global 'Rename' which will do all the relevant stuff for you. If you don't have that, you'll need to read <a href="http://arustisha.wordpress.com/2009/03/08/on-the-renaming-of-xcode-projects/">'On the Renaming of Xcode Projects'</a> and do everything there. If you're still finding your growlView is called Sample, manually open every Info.plist you can find, 'Get Info' on everything, scour through the settings for the different build environments (Debug and Release)... It took longer to rename the project than to actually build it.</p>


<p>A trivial aside, I have also added two fields to the preferences for tweet prefix and tweet postfix in exactly the same way the username and password were added. I leave the details to the interested reader.</p>


<p>You should now have a completed, installable growlView/Growl View/Growl Display/growlStyle/whatever it's actually called. You can export the current <a href="http://github.com/thingsinjars/GrowlBird">Git project</a> to have a look around or you can just download the finished <a href="http://cloud.github.com/downloads/thingsinjars/GrowlBird/GrowlBird_0.2.8.zip">GrowlBird.zip [Zip - 228KB]</a> if you like. Note, the Git project isn't guaranteed buildable at any moment in time, I might break it. The localisations still need done and the layout of the prefPane isn't the greatest, either.</p>


	<p>[<a id="note-already" href="http://thingsinjars.com/post/250/building-an-objective-c-growlview/#already">1</a>] Since writing this, I have discovered that someone else <a href="http://clickontyler.com/blog/2009/01/forward-your-growl-notifications-to-twitter/">already made a growlView</a> to do this, it just didn't show up on any of my Google searching.</p>
	<p>[<a id="note-bugged" href="http://thingsinjars.com/post/250/building-an-objective-c-growlview/#bugged">2</a>] It turns out that I did have to modify these in the end due to a <a href="http://github.com/thingsinjars/GrowlBird/commit/0647d13355aad60401b67261a5bab0a59ed4c602">silly bug</a>. Like I said, this is my first attempt at this kind of thing.</p>
      </div>
]]></description>
<pubDate>Sun, 01 Nov 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>TV Mark</title>
<link>http://thingsinjars.com/post/249/tv-mark/</link>
<guid>http://thingsinjars.com/post/249/tv-mark/</guid>
<description><![CDATA[
      <div class="teaser smallimage" id="teaser-249">
      <a href="/post/249/tv-mark/"><img src="/uploaded/images/thumbs/tvmark.com.jpg" alt="TV Mark"/></a>
      <p><a href="/post/249/tv-mark/">TV Mark</a></p>
      <p>A site which track which episodes of TV shows you have watched. You create an account and enter the name of a TV show (AJAX completed, naturally). Before the show is associated with your account, you are shown a list of broadcast episodes and you must select the latest one you have watched. You can add as many shows as you like. When you visit the site, you see something like the visual here (although with the design not totally ripped from <a href="http://codingcurious.com/">Automatic</a>) so you can instantly tell what the next unseen episode is.</p>
<p>You can ask to be notified when a new episode is broadcast in a variety of ways (twitter, e-mail, rss). Shows can be broadcast anywhere in any country and so to get around the problem of detecting when a show is broadcast, the site actually follows a collection of well-known torrent providers. <strong>Note:</strong> this site doesn't provide any links to torrents or video files, it just relies on the fact that shows usually turn up on the torrent scene shortly after they have been broadcast. You can buy episodes or seasons from iTunes or Amazon links provided next to your tracking panel.</p>
<p>The visual isn't great as there will also be some big button on each show panel to increment the last show watched.</p>    </div>
]]></description>
<pubDate>Fri, 30 Oct 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>It's not difficult, don't make it difficult</title>
<link>http://thingsinjars.com/post/248/its-not-difficult-dont-make-it-difficult/</link>
<guid>http://thingsinjars.com/post/248/its-not-difficult-dont-make-it-difficult/</guid>
<description><![CDATA[
        <div class="teaser textonly" id="teaser-248">
        <p><a href="/post/248/its-not-difficult-dont-make-it-difficult/">It's not difficult, don't make it difficult</a></p>
        <p>What's easier? Boiling a single potato, letting it cool, mashing it using a toothpick then repeating with a different potato until you have a plateful of mashed potato...</p>
<p>or </p>
<p>Boiling all the potatoes you need at once then mashing them together with a potato masher?</p>
<p>Okay, choose between one of these methods of determining whether the bathroom light is on: Draw up a list of people who have visited your house recently. Interview them to build a data set of all rooms visited and by whom. Re-interview those who visited the bathroom. Determine a timeline of bathroom visits and light switch position on entry and on exit. Analyse the data to find the last visitor to the bathroom and the position of the light switch. Examine the electrical connections between the light switch and the light bulb to determine what the current status of the light itself might be.</p>
<p>or</p>
<p>Go look.</p>
<p>How are you doing on the quiz so far? Okay. So, final question: What's easier? Building a convoluted web site using proprietary code, conflicting CSS requiring you to target everything with !important, making all interaction rely on JavaScript for even the most basic functionality, fighting between form and function so much that you end up having a website that only works occasionally and even then only works for a subset of the available users.</p>
<p>or</p>
<p>Building a straightforward website using nothing but standard mark-up, styles which cascade in a predictable fashion and enhancing already-working functionality with a dash of JavaScript to make people go 'Ooh, shiny'?</p>
<p>If you thought the second option was easier, I'm sorry, you would appear to be wrong. At least, that's the impression I get every single day while wandering round the internet. It must be really easy to make a ham-fisted, in-bred, should be kept in the basement monstrous-crime-against-nature abomination of a website because otherwise, people wouldn't do it so much.</p>
<p>I've used Opera as my main browser for almost 10 years now and I've lost count of the number of times I've been faced with a message apologising to me because it appears my browser is out of date. If I could just update my browser to Internet Explorer 5, I could enjoy their site. Seriously, it must be a lot easier to make a web page locking me out of the site than not to. It must be a matter of a few seconds work to write browser-sniffing scripts and learn all the proprietary foibles of IE whereas not writing that script must take hours and not learning bad habits must take years.</p>
<p>I have some ability to forgive those websites which are obviously the work of someone whose passion is something else. If I'm looking at a site where a guy has meticulously documented the different ways different cats react to different balls of yarn, I'm guessing his interests is in yarn. Or cats. Or the combination thereof. He's not necessarily going to know the best way to make a website. I find it much harder, however, forgive big companies. Either those with an in-house web staff or those who contract agencies. Whatever way they do it, someone is getting paid to make the website. It is someone's job to write code. </p>
<p>I've always been of the opinion that if you're going to do any thing, you should at least try to do it as well as it can possibly be done. It doesn't matter if you're playing piano, rowing, juggling chickens or making a website, you have no excuse for not at least trying to be awesome at it. If you end up being awesome at it: great! You're the world's best chicken juggler, go into the world knowing that and be happy. If you don't: great! You gave it a darn good try and you probably ended up pretty good, at least. Maybe try juggling cats next time. I have a hard enough time getting my head around the idea that not everybody follows this same level of obsession in their interests but to have people who are actually getting paid actual money to do something (in this case, making a website, not chicken juggling) and who feel it's okay to be 'okay' is a concept I have great difficulty understanding.</p>
<p>Okay, impassioned rant over. I'm not going to name any sites. Just consider this a warning, Internet.</p>      </div>
]]></description>
<pubDate>Sun, 25 Oct 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>On holiday, by the way</title>
<link>http://thingsinjars.com/post/247/on-holiday-by-the-way/</link>
<guid>http://thingsinjars.com/post/247/on-holiday-by-the-way/</guid>
<description><![CDATA[
        <div class="teaser textonly" id="teaser-247">
        <p><a href="/post/247/on-holiday-by-the-way/">On holiday, by the way</a></p>
        <p>In case any regular viewers are unaware, I'm currently on honeymoon. To tie in with this (and to celebrate the fact that my darling wife is almost as much of a geek as I am), there's a honeymoon blog to tide y'all over until I get back.</p>
<p><a href="http://madine.tumblr.com/">The Madines' travelogue</a>.</p>      </div>
]]></description>
<pubDate>Thu, 01 Oct 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Ideas</title>
<link>http://thingsinjars.com/post/245/ideas/</link>
<guid>http://thingsinjars.com/post/245/ideas/</guid>
<description><![CDATA[
        <div class="teaser textonly" id="teaser-245">
        <p><a href="/post/245/ideas/">Ideas</a></p>
        <p>To continue from the post of a month ago about how <a href="http://noodler.net">Noodle</a> was <a href="http://blah.thingsinjars.com/post/228/a-new-niche/">awesome and ahead of its time</a>, I now have to point out <a href="http://www.google.com/sidewiki/">Sidewiki</a>. Darn it, Google. Couldn't you just have bought me out? I'd have sold. Quite cheap, too...</p>
<p>Anyway. Onto the next idea. Or ideas.</p>
<p>Keen-eyed regulars (those whose don't subscribe via RSS, anyway) will have noticed the new category for '<a href="/ideas/">ideas</a>'. I may as well put all these dumb little ideas I have out there and see if anyone wants to have a go at playing with any of them. Actually, those who subscribe via <a href="http://feeds.feedburner.com/thingsinjars/zjKY">RSS</a> may have been inundated earlier with a bunch of ideas as I uploaded the backdated ones. Sorry 'bout that.</p>      </div>
]]></description>
<pubDate>Thu, 24 Sep 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Okay, unnecesary redesign</title>
<link>http://thingsinjars.com/post/233/okay-unnecesary-redesign/</link>
<guid>http://thingsinjars.com/post/233/okay-unnecesary-redesign/</guid>
<description><![CDATA[
        <div class="teaser textonly" id="teaser-233">
        <p><a href="/post/233/okay-unnecesary-redesign/">Okay, unnecesary redesign</a></p>
        <p>Not two weeks after being pleased with myself that I could subtly rejig the design without only a few lines of CSS, I decided on Friday to completely redo this site. </p>
<p>Not only did I change the layout but I've made some major changes under the hood, too. I decided to have my first attempt at an HTML5 page. Granted, it might just fall apart at any moment in any given browser but...hey, it might not.</p>
<p>On the subject of HTML5, <a href="http://en.wikipedia.org/wiki/Mark_Pilgrim">Mark Pilgrim</a> (he of the 'Dive into...' series) brought up an interesting point in the <a href="http://blog.whatwg.org/response-to-notes-on-html-5">WHATWG Blog</a> last week on the topic of whether XHTML was actually a good idea in terms of enforcing XML syntax on an HTML document:</p>It provides no perceivable benefit to users. Draconianly handled content does not do more, does not download faster, and does not render faster than permissively handled content. Indeed, it is almost guaranteed to download slower, because it requires more bytes to express the same meaning -- in the form of end tags, self-closing tags, quoted attributes, and other markup which provides no end-user benefit but serves only to satisfy the artificial constraints of an intentionally restricted syntax.<p>And, I guess, it is a good point that a well-formed XHTML document will be larger than the equivalently well-formed HTML document. If, however, developers are given a strict set of rules and a strict validator and told "make your page according to these rules, this alarm will go off if you've done it wrong", they're less likely to fall into bad habits than if they are told "These are mostly rules but sometimes suggestions, this alarm will only go off if you got things very very wrong". Mark Pilgrim is, quite rightly, focusing on the user's point of view but it just seems to me that users will also benefit from more maintainable, better structured code.</p>
<p>Of course, none of this actually matters yet and won't for the next five years or so. It probably won't matter then, either. It is only the interwebs, after all.</p>      </div>
]]></description>
<pubDate>Sun, 06 Sep 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Truly</title>
<link>http://thingsinjars.com/post/232/truly/</link>
<guid>http://thingsinjars.com/post/232/truly/</guid>
<description><![CDATA[
        <div class="teaser textonly" id="teaser-232">
        <p><a href="/post/232/truly/">Truly</a></p>
        <p>I've just updated <a href="http://trulyinnovative.com">trulyinnovative.com</a> and <a href="http://www.trulyinnovative.co.uk">www.trulyinnovative.co.uk</a>.</p>
<p>I randomly thought it was about time for a bit of a refresh but writing it, I was amazed at just how much has changed in the 3 years between the first and the second. Despite the fact that they're both supposed to be tongue-in-cheek, they are quite accurate descriptions of two different aspects of the people who 'do web'. Must remember to update them again in 2012.</p>      </div>
]]></description>
<pubDate>Wed, 02 Sep 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Not-too-subtle subtle redesign</title>
<link>http://thingsinjars.com/post/231/not-too-subtle-subtle-redesign/</link>
<guid>http://thingsinjars.com/post/231/not-too-subtle-subtle-redesign/</guid>
<description><![CDATA[
        <div class="teaser textonly" id="teaser-231">
        <p><a href="/post/231/not-too-subtle-subtle-redesign/">Not-too-subtle subtle redesign</a></p>
        <p>Okay, it's one of those occasions where I get to feel a bit smug. I decided to update the layout here a little bit, just make the content a bit wider, fonts a bit bigger, that kind of thing. Not a major restyling, just a quick once-round with the vacuum-cleaner, if you like. Less than a minute messing around with CSS later and it's done. It doesn't look like much but I was quite pleased that everything scaled nicely. It's still a bit scrappy round the edges and I wouldn't use this as a CSS showcase but I'm pleased never the less.</p>      </div>
]]></description>
<pubDate>Thu, 27 Aug 2009 00:00:00 GMT</pubDate>
<category>home</category>
</item></channel>
</rss>
