<?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>Sun, 30 Dec 12 00:00:00 -0800</lastBuildDate>
<ttl>45</ttl><item>
<title>GhostStory</title>
<link>http://thingsinjars.com/post/474/ghoststory/</link>
<guid>http://thingsinjars.com/post/474/ghoststory/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-474">
        <p><a href="http://thingsinjars.com/post/474/ghoststory/">GhostStory</a></p>
<p>During all the research I did for my CSS testing talk, I couldn't help but spot another gap where a testing tool could be useful. </p>

<h2>Cucumber</h2>

<p>Cucumber is a technology used widely in automated testing setups, mostly for acceptance testing - ensuring that the thing everybody agreed on at the beginning was the thing delivered at the end. </p>

<p>This is accomplished by having a set of plain text files containing descriptions of different scenarios or aspects of the application, usually with a description of the actions performed by an imaginary user. You describe the situation (known as a 'Given' step), describe the user's action ('When') and describe the expected outcome ('Then').</p>

<p>The language (properly known as gherkin) used in these files is deliberately simple and jargon-free so that all the key stakeholders in the project - designers, developers, product owners - can understand but the files are also written in a predictable and structured style so that they can, behind the scenes, be turned into testable code. </p>

<p>What occurred to me when looking into this area was that there wasn't an agreed terminology for specifying the layout/colour/look and feel of a project in plain text. Surely this would be the perfect place to drop in some cucumber salad. </p>

<p>What we've got now is a project based on SpookyJS - a way of controlling CasperJS (and, therefore PhantomJS) from NodeJS - which contains the GhostStory testing steps and their corresponding 'behind the scenes' test code. There are only two steps at the moment but they are the most fundamental which can be used to build up future steps. </p>

<p><p>By the way, the name 'GhostStory' only just won out over the original 'CucumberNodeSpookyCasperPhantomJS'. It kinda makes sense because it's built using a lot of ghost-named technologies (Spooky, Casper, Phantom) and cucumber test files are sometimes called "Story" files because they describe a user story.</p></p>

<h2>Implemented Steps</h2>

<p>Here, "Element descriptor" is a non-dev-readable description of the element you want to test - "Main title", "Left-hand navigation", "Hero area call-to-action". In the project, you keep a mapping file, <code>selectors.json</code>, which translates between these descriptions and the CSS selector used to identify the element in tests.</p>

<pre><code>Then the "Element descriptor" should have "property" of "value"
</code></pre>

<p>This is using the computed styles on an element and checking to see if they are what you expect them to be. I talked about something similar to this before <a href="http://thingsinjars.com/post/437/css-verification-testing/">in an earlier post</a>. This is related to the <a href="http://csste.st/techniques/frozen-dom.html">'Frozen DOM' approach</a> that my first attempt at a CSS testing tool, <a href="http://thingsinjars.com/post/438/cssert--like-assert-but-with-css-at-the-front/">cssert</a>, uses but this way does not actually involve a DOM snapshot.</p>

<pre><code>Then the "Element descriptor" should look the same as before
</code></pre>

<p>This uses the <a href="http://csste.st/techniques/image-diff.html">'Image Diff' approach</a>. You specify an element and render the browser output of that element to an image. The next time you run the test, you do the same and check to see if the two images differ. As mentioned many times before, this technique is 'content-fragile' but can be useful for a specific subset of tests or when you have mocked content. It can also be particularly useful if you have a <a href="https://speakerdeck.com/hagenburger/style-guide-driven-development">'living styleguide'</a> as described by <a href="https://twitter.com/Hagenburger/">Nico Hagenburger</a>. I've got some ideas about CSS testing on living styleguides that I'll need to write up in a later post.</p>

<h2>Future Steps</h2>

<p>Off the top of my head, there are a couple of other generic steps that I think would be useful in this project.</p>

<pre><code>Then the "Element descriptor" should have a "property" of "value1", "value2", ..., or "valueN"
</code></pre>

<p>This variation on the computed style measurement allows an arbitrary-length list of values. As long as the element being tested matches at least one of the rules, the step counts as a pass. This could be used to ensure that all text on a site is one of a certain number of font-sizes or that all links are from the predefined colour palette.</p>

<pre><code>Then the "Element descriptor" should look the same across different browsers.
</code></pre>

<p>This would build on the existing image diff step but include multiple browser runners. Just now, the image diffs are performed using <a href="https://github.com/Huddle/PhantomCSS">PhantomCSS</a> which is built on top of PhantomJS which is Webkit-based. This would ideally integrate a Gecko renderer or a Trident renderer process so that the images generated from one could be checked against another. I still feel that image diff testing is extremely fragile and doesn't cover the majority of what CSS testing needs to do but it can be a useful additional check.</p>

<h2>The aim</h2>

<p>I'm hoping this can sit alongside the other testing tools gathering on <a href="http://csste.st/">csste.st</a> where it can help people get a head-start on their CSS testing practices. What I'm particularly keen on with the GhostStory project is that it can pull in other tools and abstract them into testing steps. That way, we can take advantage of the best tools out there and stuff it into easily digested Cucumber sandwiches.</p>

<h2>Try it</h2>

<p>The GhostStory project is, naturally, <a href="https://github.com/thingsinjars/GhostStory">available on GitHub</a>. More usefully, however, I've been working on a fork of SpookyJS that integrates GhostStory into an immediately usable tool.</p>

<p>Please <a href="https://github.com/thingsinjars/SpookyJS">check out this project</a> and let me know what you think. I might rename it to distinguish it from the original SpookyJS if I can figure out exactly how to do that and maintain upstream relationships on GitHub.</p>
      </div>
]]></description>
<pubDate>Sun, 30 Dec 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Things I learnt at CSS Dev Conf</title>
<link>http://thingsinjars.com/post/473/things-i-learnt-at-css-dev-conf/</link>
<guid>http://thingsinjars.com/post/473/things-i-learnt-at-css-dev-conf/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-473">
        <p><a href="http://thingsinjars.com/post/473/things-i-learnt-at-css-dev-conf/">Things I learnt at CSS Dev Conf</a></p>
<h2>Jank</h2>

<p>This is the word <a href="http://paulirish.com/">Paul Irish</a> (<a href="https://twitter.com/paul_irish">@paul_irish</a>) used to describe that jittering, stuttering effect that happens when you aren't syncing your animations with the monitor using requestAnimationFrame. Find out more about Jank at <a href="http://jankfree.com/">jankfree.com</a> or requestAnimationFrame at <a href="http://creativejs.com/resources/requestanimationframe/">CreativeJS</a>.</p>

<h2>SuperToonists</h2>

<p><a href="http://www.rachelnabors.com/">Rachel Nabors</a> (<a href="https://twitter.com/CrowChick">@CrowChick</a>) and <a href="http://cssquirrel.com/">Kyle Weems</a> (<a href="https://twitter.com/cssquirrel">@cssquirrel</a>) are just as cool in real life as they are on the Twitter. Probably moreso, in fact, as there's more than 140 characters of them at a time.</p>

<h2>Scoped Revelation</h2>

<p><a href="http://www.xanthir.com/blog/">Tab Atkins</a> (<a href="https://twitter.com/tabatkins">@tabatkins</a>) explained over the buffet table the reason why the spec went for </p>

<pre><code>&lt;style scoped&gt;&lt;/style&gt; 
</code></pre>

<p>rather than </p>

<pre><code>&lt;scopedstyle&gt;&lt;/scopedstyle&gt;
</code></pre>

<p>It had been bugging me that using the former meant that <a href="http://thingsinjars.com/post/359/css-scoped/">this wasn't backwards compatible</a> but it turns out I was totally wrong on this one. By using the attribute rather than a new tag, the styles were backwards compatible. They would still be interpreted by older browsers (although they would still spread out to affect the whole page). If they had been included in a new tag, older browsers wouldn't have read them. The affect of the styles on the page can be avoided by introducing an ID inside the block to be scoped (and all styles within the scoped block). That way, older browsers can continue to work fine while newer browsers that interpret the attribute correctly will benefit from the improved performance of having styles only affecting a small chunk of the page. </p>

<p>This is why I don't write specs.</p>

<h2>Choose your elements wisely</h2>

<p>The examples for improving selector performance for GitHub's diff pages presented in <a href="https://twitter.com/jonrohan">Jon Rohan's</a> talk made me wonder "Do I really need all these divs?". <a href="https://speakerdeck.com/jonrohan/githubs-css-performance">Read more yourself</a>. Also, I love the word 'Design-gineer'.</p>

<h2>A Porter?</h2>

<p><a href="http://thewebivore.com/">Pam Selle</a> (<a href="https://twitter.com/pamasaur">@pamasaur</a>) couldn't believe I had never heard of a porter beer. Is this actually a thing? Wikipedia seems to think so but then, Wikipedia can be convinced that Julianne Moore is Dudley Moore's daughter so I'll need more proof than that. Ale, stout, bitter, lager, all words I'm familiar with but 'porter'? Nope.</p>

<h2>More than you'd think</h2>

<p>I thought I had a fairly comprehensive list of all the CSS testing tools out there. Really. I've spent over a year researching and testing as many as I could get my hands on. There are even more. <a href="http://philipwalton.com/">Phil Walton</a> (<a href="https://twitter.com/philwalton">@philwalton</a>) made some excellent points around mocking content for tests that I'm going to have to follow up on.</p>

<h2>Skyscraper</h2>

<p><a href="http://christopherschmitt.com/">Christopher Schmitt</a> (<a href="https://twitter.com/teleject">@teleject</a>) is tall. Really tall. No, taller than that.</p>
      </div>
]]></description>
<pubDate>Mon, 17 Dec 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>CSS Dev Conf</title>
<link>http://thingsinjars.com/post/472/css-dev-conf/</link>
<guid>http://thingsinjars.com/post/472/css-dev-conf/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-472">
        <p><a href="http://thingsinjars.com/post/472/css-dev-conf/">CSS Dev Conf</a></p>
<p>Last week I was at <a href="http://cssdevconf.com/">CSS Dev Conf</a> in Hawaii - the first of an annual series of conferences. Not only was I there, I actually gave a talk!</p>

<p>I gave an overview of the tools and techniques available for automated CSS testing. I didn't mention it much here or on twitter because, well, I was kinda nervous and didn't want to jinx it. In my daily job, I organise Tech Talks and give pointers to people on how to make their presentations exciting and full of awsm but I tend to avoid actually standing up at the front of the room myself. Beyond introducing the speakers, that is. This is probably why I used to <a href="http://www.tigerfest.co.uk/">help organise gigs</a> more than play them.</p>

<p>I won't repeat the content of the talk here. For that, you should start out by <a href="http://csste.st/slides/">checking out the slides</a>. The main point I finished on, however, is that the web dev community has fantastic tools for testing every aspect of web development except CSS and that it appears that every developer interested in the subject has started from scratch and built a tool that does what they need it to do. I'm hoping that I can turn <a href="http://csste.st/">http://csste.st/</a> into a community-driven site where people can share best-practices, techniques, tools and terminology around CSS testing. That way, we can create some sturdy processes around testing our CSS and not reinvent the wheel every few months.</p>

<h2>The conference</h2>

<p>Firstly, the trip to Hawaii: it was fantastic. I spent the weekend before the conference staying in a backpackers hostel on Waikiki beach. If you ever need somewhere to stay for a fraction of the price of a hotel on Waikiki, I totally recommend the 'Waikiki Backpackers Hostel'. Backpackers' hostels are the same everywhere - there are the people who hang around reception that may or may not work there, you can't quite tell; there's the Australian guy who comes down drunk for breakfast, smokes half-a-dozen cigarettes quickly then goes back to bed until the afternoon; there's the guy in his mid 70s who looks like a cross between everybody's favourite grandad and a stereotypical acid-casualty.</p>

<p>I swam with turtles in Hanauma Bay, climbed up Diamonhead Ridge, took a bus to the far side of downtown then spent 4 hours walking back via Iolani Palace. Like I say, it was a fantastic trip, even for someone who doesn't like the sun that much.</p>

<p>On the Tuesday, I moved into the Outrigger Reef on the Beach hotel for the conference. Ooh, posh. I could practically step out of my room into the elevator then step out of the elevator onto the beach. I then got to spend my remaining time in Hawaii hanging out with a huge bunch of cool, clever people (<a href="https://twitter.com/CrowChick/css-dev-conf-2012/members">Rachel Nabors put together a Twitter list of the speakers</a>), all of whom know an awful lot about web development. </p>

<p>With any multi-track conference there are always going to be a few sessions you have to miss but with CSS Dev Conf being four-track and having such a high level of quality, I kinda worry that I missed out on about three-quarters of what I wanted to see. Fortunately, everybody's been sharing their slides so I can at least get the gist of what they were talking about.</p>

<h2>The journey</h2>

<p>All in all, I'd totally recommend keeping an eye open for the announcement of next year's CSS Dev Conf. It might not be held in Honolulu again but, from my point of view, that's a good thing. It really is a fantastic place to spend time (seriously: turtles!) but getting there from Berlin is not the easiest thing. In fact, if you use the 'Earth Sandwich' lab on <a href="http://here.com/">here.com</a>, you can see how close Hawaii is to being the Exact Opposite Side of the World from Berlin. On the way out there, it didn't seem too bad as I left on Friday morning (Berlin time) and landed on Friday evening (Hawaii time) but on the way back, I left on Thursday and landed on Saturday. That was quite a journey.</p>
      </div>
]]></description>
<pubDate>Sun, 16 Dec 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>jHERE playground</title>
<link>http://thingsinjars.com/post/471/jhere-playground/</link>
<guid>http://thingsinjars.com/post/471/jhere-playground/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-471">
        <p><a href="http://thingsinjars.com/post/471/jhere-playground/">jHERE playground</a></p>
<p>Every couple of months, we have a Research Week. It's kind of like the well-known <a href="http://googleblog.blogspot.de/2006/05/googles-20-percent-time-in-action.html">Google 20% time</a> but instead of doing it one day a week, we gather up our time and do a week of maps-based hacking. It's totally cross-discipline so we usually gather a couple of developers, a couple of UX and visual designers, a QA and build something cool. In past Research Weeks, I've built or helped build the <a href="http://here.com/alien">Alien Easter Egg</a>, <a href="http://conversations.nokia.com/2012/11/09/groupon-weather-and-more-on-maps-nokia-com/">Maps Labs</a> and <a href="http://covermap.me">CoverMap.Me</a>. I also built a maps-based JSBin fork called JotApp.</p>

<p>When my partner-in-crime <a href="http://marcon.me/">Max</a> started working on the latest version of his <a href="http://jhere.net">jQuery plugin</a> (formerly called jOvi, now called jHERE), I wanted to build a new playground where people could play and build their own maps mashups and hacks really easily. My first thought was to rework the fork of <a href="http://jsbin.com">JSBin</a> again and maybe add in a slightly nicer default theme. I wanted users to be able to save to Gists so, seeing as there is already an SQLite and a MySQL adapter, I wrote a Gist adapter which appeared to the application as if it were a database but actually saved to anonymous Gists. The problem was that it was a bit too… heavy.</p>

<p>Don't get me wrong, JSBin is a fantastic project. It just does a lot more than I needed. I didn't need the MySQL adapter, the alternate themes, the localstorage or the user registration. Also, it's a bit too weighty for my phone. When someone tweets a link to a JSBin or a JSFiddle, I usually check it out on my phone and it's not the best experience. Seeing as HERE maps work on mobile, I wanted my playground to work, too. Rather than spend a couple of hours cutting out all the bits I didn't want from JSBin, I decided to spend a couple of hours building my own version from scratch. So, this past Sunday afternoon, that's exactly what I did:</p>

<p><a href="http://bin.jhere.net">jHERE Playground</a></p>

<p><a href="http://bin.jhere.net"><img src="http://thingsinjars.com/uploaded/images/expanded/jHERE-Playground.png" alt="jHERE Playground on Mobile" /></a></p>

<p>It's written in NodeJS on top of express and works nicely on desktop, iPad and mobile.</p>

<p>The project is open-sourced on <a href="https://github.com/thingsinjars/map-playground">GitHub</a> (naturally) and can be modified to be a general JS-playground for anything. If you fancy a simple, self-hosted JS hackspace, just change the default HTML, CSS and JS and it's ready to go.</p>
      </div>
]]></description>
<pubDate>Tue, 13 Nov 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Open Source Snacks</title>
<link>http://thingsinjars.com/post/470/open-source-snacks/</link>
<guid>http://thingsinjars.com/post/470/open-source-snacks/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-470">
        <p><a href="http://thingsinjars.com/post/470/open-source-snacks/">Open Source Snacks</a></p>
<p>In my opinion, seed snacks are pretty much the perfect web dev snack: they're tasty, they're low-fat, they're vegan-friendly, they're gluten-free. I've always got a tub of some next to my monitor so, when I'm chewing over a tricky layout, I can grab a handful and chew them, too. </p>

<p><a href="https://github.com/thingsinjars/opensourcesnacks">This repository</a> collects some of my favourite seed recipes and I'm hoping that other web devs can clone the project, roast their own, suggest improvements and submit a pull request. If you have any other easy to make snacks (such as nut snack recipes), feel free to submit them, too.</p>

<h2>Eating tips</h2>

<p>From observation, seed eaters tend to fall into one of these categories: </p>

<h3>Pour-and-snarf</h3>

<p><img src="https://raw.github.com/thingsinjars/opensourcesnacks/master/images/seed-snackers/pour-snarf.png" alt="Pour and Snarf" title="Pour and Snarf" /></p>

<p>Pour a few into your hand, tip them into your mouth in a oner. Good when you're in a hurry. Can lead to stray seeds falling into the keyboard.</p>

<h3>Considerate Ant-eater</h3>

<p><img src="https://raw.github.com/thingsinjars/opensourcesnacks/master/images/seed-snackers/considerate-ant-eater.png" alt="Considerate Ant-eater" title="Considerate Ant-eater" /></p>

<p>Pour a few into your hand, stick your tongue into the pile of seeds, retract. </p>

<h3>Solo Ant-eater</h3>

<p><img src="https://raw.github.com/thingsinjars/opensourcesnacks/master/images/seed-snackers/solo-ant-eater.png" alt="Solo Ant-eater" title="Solo Ant-eater" /></p>

<p>Stick your tongue directly into the tub of seeds. Clean, efficient, not good for sharing.</p>

<h3>Ice-cream scoop</h3>

<p><img src="https://raw.github.com/thingsinjars/opensourcesnacks/master/images/seed-snackers/ice-cream-scoop.png" alt="Ice-cream scoop" title="Ice-cream scoop" /></p>

<p>Use a spoon. Good for sharing and minimises mess. Prevents multi-tasking. Feels kind of like using your mouse to go Edit > Copy when ctrl-C is right there.</p>

<h2>Rousing call-to-arms</h2>

<p>The stereotypical image of the geek - bottle of cola on one side, jumbo bag of chips on the other, little desire to do anything beyond the computer - has never really been true for the majority. We're all kinds of different people - mountain climbers, cyclists, needlepoint workers, knitters. The people that played on the football team and the ones who didn't get picked. We deserve more than just nachos.</p>

<p>Also nachos.</p>



<p><img src="https://raw.github.com/thingsinjars/opensourcesnacks/master/images/small-logo.png" alt="Open Source Snacks" title="Open Source Snacks" /></p>

<p><a href="https://github.com/thingsinjars/opensourcesnacks">Clone on GitHub</a></p>

<p><a href="http://thenounproject.com/noun/sunflower-seed/#icon-No1710">Sunflower Seed</a> designed by <a href="http://thenounproject.com/m3d">Dmitry Sholkov</a> from The Noun Project</p>
      </div>
]]></description>
<pubDate>Tue, 30 Oct 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Some App.net recipes</title>
<link>http://thingsinjars.com/post/469/some-appnet-recipes/</link>
<guid>http://thingsinjars.com/post/469/some-appnet-recipes/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-469">
        <p><a href="http://thingsinjars.com/post/469/some-appnet-recipes/">Some App.net recipes</a></p>
<p>This is a collection of code snippets for various common tasks you might need to accomplish with the <a href="https://github.com/appdotnet/api-spec">App.net API</a>. Most of these are focused on creating or reading geo-tagged posts. They require a developer account on app.net and at least one of an App ID, App Code, App Access Token or User Access Token. The calls here are implemented using jQuery but that's just to make it easier to copy-paste into the console to test them out (so long as you fill in the blanks). </p>

<p>An important thing to bear in mind is the possibility for confusion between a 'stream' and 'streams'. By default, a 'stream' is a discrete chunk of the 20 latest posts served at a number of endpoints. This is the open, public, <a href="https://alpha-api.app.net/stream/0/posts/stream/global">global stream</a>:</p>

<pre><code>https://alpha-api.app.net/stream/0/posts/stream/global
</code></pre>

<p>On the other hand, 'streams' are long-poll connections that serve up any matching posts as soon as they are created. The connection stays open while there is something there to receive the response. Streams are available under:</p>

<pre><code>https://alpha-api.app.net/stream/0/streams
</code></pre>

<p>Totally not confusing. Not at all.</p>



<h2>Creating a user access token</h2>

<p>Required for any user-specific data retrieval. The only tricky thing you'll need to think about here is the <code>scope</code> you require.</p>

<pre><code>scope=stream email write_post follow messages export
</code></pre>

<p>should cover most requirements.</p>

<h3>Requires</h3>

<ul>
<li><code>client_id</code></li>
</ul>

<p>Visit this URL:</p>

<pre><code>https://alpha.app.net/oauth/authenticate
    ?client_id=[your client ID]
    &amp;response_type=token
    &amp;redirect_uri=http://localhost/
    &amp;scope=stream email write_post follow messages export
</code></pre>



<h2>Using a user access token to create a post (with annotations)</h2>

<h3>Requires</h3>

<ul>
<li><code>User Access Token</code></li>
<li>text to post</li>
</ul>

<p>The text is essential if you don't mark a post as '<code>machine_only</code>'. The annotations here are optional. Annotations don't appear in the global stream unless the requesting client asks for them.</p>

<pre><code>$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({
    "annotations": [{
      "type": "net.app.core.geolocation",
      "value": {
        "latitude": 52.5,
        "longitude": 13.3,
        "altitude": 0,
        "horizontal_accuracy": 100,
        "vertical_accuracy": 100
      }
    }],
    "text": "Don't mind me, just checking something out."
  }),
  dataType: 'json',
  success: function(data) {
    console.log("Text+annotation message posted");
  },
  error: function() {
    console.log("Text+annotation message failed");
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/posts?access_token={USER_ACCESS_TOKEN}'
});
</code></pre>



<h2>Using a user access token to post a machine_only post (with annotations)</h2>

<h3>Requires</h3>

<ul>
<li><code>User Access Token</code></li>
</ul>

<p>In this example, we're creating a post that won't show up in user's timelines and adding the 'well-known annotation' for geolocation.</p>

<pre><code>$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({
    "annotations": [{
      "type": "net.app.core.geolocation",
      "value": {
        "latitude": 52.5,
        "longitude": 13.3,
        "altitude": 0,
        "horizontal_accuracy": 100,
        "vertical_accuracy": 100
      }
    }],
    machine_only: true
  }),
  dataType: 'json',
  success: function(data) {
    console.log("Non-text message posted");
  },
  error: function() {
    console.log("Non-text message failed");
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/posts?access_token={USER_ACCESS_TOKEN}'
});
</code></pre>



<h2>Retrieve the global stream, including geo-annotated posts if there are any</h2>

<h3>Requires</h3>

<ul>
<li><code>User Access Token</code></li>
</ul>

<p>This is a very basic call to retrieve the <a href="https://alpha-api.app.net/stream/0/posts/stream/global">global stream</a> but it also instructs the endpoint to return us all annotations and include machine-only posts.</p>

<pre><code>var data = {
  "include_machine": 1,
  "include_annotations": 1,
  "access_token": "{USER_ACCESS_TOKEN}"
};

$.ajax({
    contentType: 'application/json',
    dataType: 'json',
    success: function(data) {
      console.log(data);
    },
    error: function(error, data) {
      console.log(error, data);
    },
    type: 'GET',
    url: 'https://alpha-api.app.net/stream/0/posts/stream/global',
    data: data
});
</code></pre>



<h2>Creating an App Access Token</h2>

<p>This is necessary for many of the <code>streams</code> operations. It is not used for individual user actions, only for application-wide actions. </p>

<ul>
<li><a href="https://github.com/appdotnet/api-spec/blob/master/auth.md#app-access-token-flow">App.net API wiki on App Access Tokens</a></li>
</ul>

<h3>Requires</h3>

<ul>
<li><code>client_id</code></li>
<li><code>client_secret</code></li>
</ul>

<p><code>client_credentials</code> is one of the four types of <code>grant_type</code> specified in the <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-31">OAuth 2.0 specification</a>. I had difficulty getting this to work when using a data object:</p>

<pre><code>var data = {
    "client_id": "{CLIENT_ID}",
    "client_secret":"{CLIENT_SECRET}",
    "grant_type": "client_credentials"
};
</code></pre>

<p>The <code>client_credentials</code> kept throwing an error. Instead, sending this as a string worked fine:</p>

<pre><code>$.ajax({
  contentType: 'application/json',
  data: 'client_id={CLIENT_ID}&amp;client_secret={CLIENT_SECRET}&amp;grant_type=client_credentials',
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, data) {
    console.log(error, data);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha.app.net/oauth/access_token'
});
</code></pre>

<p>One other thing to note is that this bit should be done server-side. This will throw a bunch of "…not allowed by Access-Control-Allow-Origin…" errors if you do it via jQuery.</p>

<h3>Returns</h3>

<pre><code>{
    "access_token": "{APP_ACCESS_TOKEN}"
    }
</code></pre>



<h2>Creating a <code>streams</code> format</h2>

<p>Now you have your app access token, you can use it to tell the service what kind of data you want back. The streams offered in the API have two quite powerful aspects. Firstly, filters allow you to run many kinds of queries on the data before it is streamed to you so you don't need to recieve and process it all. Secondly, the decoupling of filters from streams means you can specify the data structure and requirements you want once then just access that custom endpoint to get the data you want back any time.</p>

<h3>Requires</h3>

<ul>
<li><code>App access token</code></li>
</ul>

<p>This first example just creates an unfiltered stream endpoint</p>

<pre><code>$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({"object_types": ["post"], "type": "long_poll", "id": "1"}),
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, responseText, response) {
    console.log(error, responseText, response);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/streams?access_token={APP_ACCESS_TOKEN}'
});
</code></pre>

<h3>Returns</h3>

<pre><code>{
    "data": {
        "endpoint": "https://stream-channel.app.net/channel/1/{LONG_RANDOM_ENDPOINT_URL}",
        "id": "77",
        "object_types": [
            "post"
        ],
        "type": "long_poll"
    },
    "meta": {
        "code": 200
    }
}
</code></pre>



<h2>Using Filters to create a stream of geotagged posts</h2>

<p>We'll specify some requirements for our filter now so that it only returns back a subset of posts. The rules we're specfying here are:</p>

<pre><code>At least one item in the "/data/annotations/*/type" field
must "match"
the value "net.app.core.geolocation"
</code></pre>

<h3>Requires</h3>

<ul>
<li><code>User access token</code></li>
</ul>

<p>The <code>field</code> is specified in '<a href="http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-02">JSON Pointer</a>' format. Within the response, there is a 'data' object and a 'meta' object. The data contains an 'annotations' object which contains an array of annotations, each of which has a type. This is represented as <code>/data/annotations/*/type</code>.</p>

<pre><code>$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({"match_policy": "include_any", "clauses": [{"object_type": "post", "operator": "matches", "value": "net.app.core.geolocation", "field": "/data/annotations/*/type"}], "name": "Geotagged posts"}),
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, responseText, response) {
    console.log(error, responseText, response);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/filters?access_token={USER_ACCESS_TOKEN}'
});
</code></pre>

<h3>Returns</h3>

<p>The filter rules you just specified, the <code>id</code> of the filter (remember that for later) and the details of the application used to make the request.</p>

<pre><code>{
"clauses": [
    {
        "field": "/data/annotations/*/type",
        "object_type": "post",
        "operator": "matches",
        "value": "net.app.core.geolocation"
    }
],
"id": "527",
"match_policy": "include_any",
"name": "Geotagged posts",
"owner": {
    "avatar_image": {
        "height": 200,
        "url": "https://d2rfichhc2fb9n.cloudfront.net/image/4/Pr63PjEwJ1fr5Q4KeL3392BMgSnIAYlHxv8OkWwzx75V8quNfpaFp4VPpKnDRxdXtYYPtIutrDVdU9NbJn7hKApQL84T5sfB1D9bWTgtizMWInignv0WyPPfM2DpqSThQgvkB68vbPzjZ8VeKM02M2GySZ4",
        "width": 200
    },
    "canonical_url": "https://alpha.app.net/thingsinjars",
    "counts": {
        "followers": 30,
        "following": 65,
        "posts": 96,
        "stars": 0
    },
    "cover_image": {
        "height": 230,
        "url": "https://d2rfichhc2fb9n.cloudfront.net/image/4/UWZ6k9xD8_8LzEVUi_Uz6C-Vn-I8uPGEBtKb9jSVoFNijTwyEm1mJYpWq6JvnA6Jd4gzW76vFnbSWvM3jadhc1QxUl9qS4NTKiv3gJmr1zY_UpFWvX3qhOIyKrBPZckf2MrinqWay3H0h9rfqY0Gp9-liEg",
        "width": 960
    },
    "created_at": "2012-08-12T17:23:44Z",
    "description": {
        "entities": {
            "hashtags": [],
            "links": [],
            "mentions": []
        },
        "html": "&lt;span itemscope="https://app.net/schemas/Post"&gt;Nokia Maps Technologies Evangelist; CreativeJS team member; the tech side of museum140; builder of The Elementals; misuser of semi-colons;rn&lt;/span&gt;",
        "text": "Nokia Maps Technologies Evangelist; CreativeJS team member; the tech side of museum140; builder of The Elementals; misuser of semi-colons;rn"
    },
    "id": "3191",
    "locale": "en_GB",
    "name": "Simon Madine",
    "timezone": "Europe/Berlin",
    "type": "human",
    "username": "thingsinjars"
}
}
</code></pre>



<h2>Listening to the geotagged post stream</h2>

<p>This wil return a link to a long-lasting connection to the app.net stream that will only return posts with the geolocation annotation.</p>

<h3>Requires</h3>

<ul>
<li><code>filter_id</code> from the previous call</li>
</ul>

<p>Note: the <code>filter_id</code> was returned as <code>id</code> in the previous response.</p>

<pre><code>$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({"object_types": ["post"], "type": "long_poll", "filter_id": "527"}),
  dataType: 'json',
  success: function(data) {
    console.log(data);
  },
  error: function(error, responseText, response) {
    console.log(error, responseText, response);
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/streams?access_token={APP_ACCESS_TOKEN}'
});
</code></pre>

<h3>Returns</h3>

<p>The same kind of response as the 'Creating a <code>streams</code> format' example except the data coming down on the stream is filtered.</p>

<pre><code>https://stream-channel.app.net/channel/1/{LONG_RANDOM_ENDPOINT_URL}
</code></pre>

<p>Open that URL up in your browser (seeing as we're testing) and, in a different tab, create a geo-tagged machine-only post (see above). Your post will appear almost instantly after you've submitted it.</p>
      </div>
]]></description>
<pubDate>Mon, 29 Oct 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Location-based time</title>
<link>http://thingsinjars.com/post/468/location-based-time/</link>
<guid>http://thingsinjars.com/post/468/location-based-time/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-468">
        <p><a href="http://thingsinjars.com/post/468/location-based-time/">Location-based time</a></p>
<p>Inspired by the simplicity of <a href="http://thingsinjars.com/post/466/building-a-proximity-search/">implementing a proximity search using MongoDB</a>, I found myself keen to try out another technology.</p>

<p>It just so happened that I was presented with a fun little problem the other day. Given a latitude and longitude, how do I <strong>quickly</strong> determine what the time is? Continuing the recent trend, I wanted to solve this problem with Node.JS.</p>

<p>Unsurprisingly, there's a lot of information out there about timezones. Whenever I've worked with timezones in the past, I've always gotten a little bit lost so this time, I decided to actually read a bit and find out what was supposed to happen. In essence, if you're doing this sort of task. you do not want to have to figure out the actual time yourself. Nope. It's quite similar to one of my top web dev rules:</p>


  <p>Never host your own video.</p>


<p><strong>(Really, never deal with video yourself. Pay someone else to host it, transcode it and serve it up. It'll will always work out cheaper.)</strong></p>

<p>What you want to do when working with timezones is tie into someone else's database. There are just too many rules around international boundaries, summer time, leap years, leap seconds, countries that have jumped over the international date line (more than once!), islands whose timezone is 30 minutes off the adjacent ones...</p>

<p>To solve this problem, it needs to be split into two: the first part is to determine which timezone the coordinate is in, the second is the harder problem of figuring out what time it is in that timezone. Fortunately, there are other people who are already doing this. Buried near the back of the bottom drawer in very operating system is some version of the <code>tz database</code>. You can spend hours <a href="http://en.wikipedia.org/wiki/Tz_database">reading up about it</a>, its controversies and history on Wikipedia if you like. More relevantly, however, is what it can do for us in this case. Given an IANA timezone name – "America/New_York", "Asia/Tokyo" – you can retrieve the current time from the system's <code>tz database</code>. I don't know how it works. I don't need to know. It works.</p>

<h2>Node</h2>

<p>Even better for reaching a solution to this problem, <a href="https://npmjs.org/package/zoneinfo">there's a node module</a> that will abstract the problem of loading and querying the database. If you use the <code>zoneinfo</code> module, you can create a new timezone-aware Date object, pass the timezone name to it and <strong>it</strong> will do the hard work. awsm. The module wasn't perfect, however. It loaded the system database synchronously using <code>fs.readFileSync</code> which is I/O blocking and therefore a <em>Bad Thing</em>. Boo.</p>

<p>10 minutes later and <a href="http://marcon.me/">Max</a> had wrangled it into using the asynchronous, non-blocking <code>fs.ReadFile</code>. Hooray!</p>

<p>Now all I needed to do was figure out how to do the first half of the problem: map a coordinate to a timezone name.</p>

<h2>Nearest-Neighbour vs Point-in-Polygon</h2>

<p>There are probably more ways to solve this problem but these were the two routes that jumped to mind. The tricky thing is that the latitude and longitude provided could be arbitrarily accurate. A simple lookup table just wouldn't work. Of course, the core of the problem was that we needed to figure out the answer fast.</p>

<h3>Nearest Neighbour</h3>

<ol>
<li>Create a data file containing a spread of points across the globe, determine (using any slow solution) the timezone at that point.</li>
<li>Load the data into an easily searchable in-memory data-structure (such as a <a href="http://en.wikipedia.org/wiki/K-d_tree">k-d tree</a>)</li>
<li>Given a coordinate, find the nearest existing data point and return its value.</li>
</ol>

<h3>Point in Polygon</h3>

<ol>
<li>Create a data file specifying the geometry of all timezones.</li>
<li>Given a coordinate, loop over each polygon and determine whether this coordinate is positioned inside or outside the polygon.</li>
<li>Return the first containing polygon</li>
</ol>

<p>This second algorithm could be improved by using a coarse binary search to quickly reduce the number of possible polygons that contain this point before step 2.</p>

<p>Despite some kind of qualification in mathematic-y computer-y stuff, algorithm analysis isn't my strong point. To be fair, I spent the first three years of my degree trying to get a record deal and the fourth trying to be a stand-up comedian so we may have covered complexity analysis at some point and I just didn't notice. What I do know, however, is that k-d trees are fast for searching. Super fast. They can be a bit slower to create initially but the point to bear in mind is that you only load it once while you search for data lots. On the other hand, while it's a quick task to load the geometry of a small number of polygons into memory, determining which polygon a given point is in can be slow, particularly if the polygons are complex.</p>

<p>Given this vague intuition, I settled on the first option. </p>

<p>If I wanted to create a spread of coordinates and their known timezones from scratch, it might have been an annoyingly slow process but, the Internet being what it is, someone already did the hard work. <a href="https://gist.github.com/1769458">This gist</a> contains the latitude and longitude for every city in the world and what IANA timezone it is in. Score! A quick regex later and it looks like this:</p>

<pre><code>module.exports = [
  {"latitude": 42.50729, "longitude": 1.53414, "timezone": "Europe/Andorra"},
  {"latitude": 42.50779, "longitude": 1.52109, "timezone": "Europe/Andorra"},
  {"latitude": 25.56473, "longitude": 55.55517, "timezone": "Asia/Dubai"},
  {"latitude": 25.78953, "longitude": 55.9432, "timezone": "Asia/Dubai"},
  {"latitude": 25.33132, "longitude": 56.34199, "timezone": "Asia/Dubai"},
  etc…
</code></pre>

<p>(<a href="https://github.com/thingsinjars/coordinate-tz/blob/master/city_timezones.js">See the original on GitHub</a>)</p>

<p>All that's left is to load that into a k-d tree and we've got a fully-searchable, fast nearest neighbour lookup.</p>

<h2>Source</h2>

<p>The source for this node module is, of course, <a href="https://github.com/thingsinjars/coordinate-tz">available on GitHub</a> and the module itself is available for <a href="https://npmjs.org/package/coordinate-tz">install via npm</a> using:</p>

<pre><code>npm install coordinate-tz
</code></pre>

<p>When combined with the <a href="https://npmjs.org/package/zoneinfo"><code>zoneinfo</code> module </a> (or, even better, <a href="https://github.com/mmarcon/node-zoneinfo">this async fork of the module</a>), you can get a fast, accurate current time lookup for any latitude and longitude.</p>

<p>Not a bad little challenge for a Monday evening.</p>
      </div>
]]></description>
<pubDate>Mon, 15 Oct 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Explanating Experiment Follow-up</title>
<link>http://thingsinjars.com/post/467/explanating-experiment-follow-up/</link>
<guid>http://thingsinjars.com/post/467/explanating-experiment-follow-up/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-467">
        <p><a href="http://thingsinjars.com/post/467/explanating-experiment-follow-up/">Explanating Experiment Follow-up</a></p>
<p>A year ago, I started <a href="http://thingsinjars.com/post/428/explanating/">a little experiment</a> (and not one of my usual <a href="http://thelab.thingsinjars.com">web experiments</a>). </p>

<p>I decided to give away my book, <a href="http://explanating.com">Explanating</a>, for free. The website has links to download the book without charge and also links through to <a href="https://www.amazon.co.uk/dp/B00492CJE0">Amazon</a> and <a href="http://www.lulu.com/content/e-book/explanating/9593879">Lulu</a>. I asked people to download the free one then, if they enjoyed it, they could come back and buy it.</p>

<p>Twelve months later, I now have the answer. </p>

<ul>
<li>Free: 315</li>
<li>Amazon: 2</li>
<li>Lulu: 0</li>
</ul>

<p>Erm. Yeah. Not quite as successful as I would have liked. Still, the point was to measure the 'conversion rate'. Admittedly, it's a small sample size but it would appear to be about 0.6%. At this rate, I only need another 97,465,886 people to download the free one and I'll have made £1,000,000! Sweet!</p>
      </div>
]]></description>
<pubDate>Sat, 27 Oct 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Building a Proximity Search</title>
<link>http://thingsinjars.com/post/466/building-a-proximity-search/</link>
<guid>http://thingsinjars.com/post/466/building-a-proximity-search/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-466">
        <p><a href="http://thingsinjars.com/post/466/building-a-proximity-search/">Building a Proximity Search</a></p>
<p>This is the detailed post to go with <a href="http://thingsinjars.com/post/465/proximity-search/">yesterday's quick discussion about proximity search</a>. All the code is <a href="https://github.com/thingsinjars/Proximity">available on GitHub</a>.</p>

<p>This assumes a bit of <a href="http://nodejs.org/">NodeJS</a> knowledge, a working copy of <a href="http://mxcl.github.com/homebrew/">homebrew</a> or something similar.</p>

<h2>Install</h2>

<ul>
<li>MongoDB - <code>brew install mongodb</code></li>
<li><a href="http://nodejs.org/">NodeJS</a></li>
<li>NPM (included in NodeJS installer these days)</li>
</ul>

<p>These are included in the <a href="https://github.com/thingsinjars/Proximity/blob/master/package.json"><code>package.json</code></a> but it can't hurt to mention them here:</p>

<ul>
<li><code>npm install twitter</code> (node twitter streaming API library)</li>
<li><code>npm install mongodb</code> (native mongodb driver for node)</li>
<li><code>npm install express</code> (for convenience with API later)</li>
</ul>

<p>Start <code>mongod</code> in the background. We don't quite need it yet but it needs done at some point, may as well do it now.</p>

<h2>Create a Twitter App</h2>

<p><a href="https://dev.twitter.com/apps/new">Fill out the form</a> Then press the button to get the single-user access token and key. I love that Twitter does this now, rather than having to create a full authentication flow for single-user applications.</p>

<h2>ingest.js</h2>

<p><em>(open the <a href="https://github.com/thingsinjars/Proximity/blob/master/ingest.js">ingest.js</a> file and read along with this bit)</em></p>

<p>Using the basic native MongoDB driver, everything must be done in the <code>database.open</code> callback. This might lead to a bit of Nested Callback Fury but if it bothers you or becomes a bit too furious for your particular implementation, there are a couple of alternative Node-MongoDB modules that abstract this out a bit.</p>

<pre><code>// Open the proximity database
db.open(function() {
    // Open the post collection
    db.collection('posts', function(err, collection) {
        // Start listening to the global stream
        twit.stream('statuses/sample', function(stream) {
            // For each post
            stream.on('data', function(data) {
                if ( !! data.geo) {
                    collection.insert(data);
                }
            });
        });
    });
});
</code></pre>

<h2>Index the data</h2>

<p>The hard work has all been done for us: <a href="http://www.mongodb.org/display/DOCS/Geospatial+Indexing/">Geospatial Indexing in MongoDB</a>. That's a good thing.</p>

<p>Ensure the system has a Geospatial index on the tweets.</p>

<pre><code>db.posts.ensureIndex({"geo.coordinates" : "2d"})
</code></pre>

<p>Standard Geospatial search query:</p>

<pre><code>db.posts.find({"geo.coordinates": {$near: [50, 13]}}).pretty()
(find the closest points to (50,13) and return them sorted by distance)
</code></pre>

<p>By this point, we've got a database full of geo-searchable posts and a way to do a proximity search on them. To be fair, it's more down to mongodb than anything we've done.</p>

<p>Next, we extend the search on those posts to allow filtering by query</p>



<pre><code>db.posts.find({"geo.coordinates": {$near: [50, 13]}, text: /.*searchterm.*/}).pretty()
</code></pre>

<h2>API</h2>

<p>Super simple API, we only have two main query types:</p>

<ul>
<li><code>/proximity?latitude=55&amp;longitude=13</code></li>
<li><code>/proximity?latitude=55&amp;longitude=13&amp;q=searchterm</code></li>
</ul>

<p>Each of these can take an optional <code>'callback'</code> parameter to enable <code>jsonp</code>. We're using express so the callback parameter and content type for returning JSON are both handled automatically.</p>

<p><code>api.js</code></p>

<p><em>(open the <a href="https://github.com/thingsinjars/Proximity/blob/master/api.js">api.js</a> file and read along with this bit)</em></p>

<p>This next chunk of code contains everything so don't panic.</p>

<pre><code>db.open(function() {
  db.collection('posts', function(err, collection) {
    app.get('/proximity', function(req, res) {
      var latitude, longitude, q;
      latitude = parseFloat(req.query["latitude"]);
      longitude = parseFloat(req.query["longitude"]);
      q = req.query["q"];

      if (/^(-?d+(.d+)?)$/.test(latitude) &amp;&amp; /^(-?d+(.d+)?)$/.test(longitude)) {
        if (typeof q === 'undefined') {
          collection.find({
            "geo.coordinates": {
              $near: [latitude, longitude]
            }
          }, function(err, cursor) {
            cursor.toArray(function(err, items) {
              writeResponse(items, res);
            });
          });
        } else {
          var regexQuery = new RegExp(".*" + q + ".*");
          collection.find({
            "geo.coordinates": {
              $near: [latitude, longitude]
            },
            'text': regexQuery
          }, function(err, cursor) {
            cursor.toArray(function(err, items) {
              writeResponse(items, res);
            });
          });
        }
      } else {
        res.send('malformed lat/lng');
      }

    });
  });
});
</code></pre>

<p>If you've already implemented the <code>ingest.js</code> bit, the majority of this <code>api.js</code> will be fairly obvious. The biggest change is that instead of loading the data stream then acting upon each individual post that comes in, we're acting on URL requests.</p>

<pre><code>app.get('/proximity', function(req, res) {
</code></pre>

<p>For every request on this path, we try and parse the query string to pull out a latitude, longitude and optional query parameter.</p>

<pre><code>if (/^(-?d+(.d+)?)$/.test(latitude) &amp;&amp; /^(-?d+(.d+)?)$/.test(longitude)) {
</code></pre>

<p>If we <strong>do</strong> have valid coordinates, pass through to Mongo to do that actual search:</p>

<pre><code>collection.find({
  "geo.coordinates": {
    $near: [latitude, longitude]
  }
}, function(err, cursor) {
  cursor.toArray(function(err, items) {
    writeResponse(items, res);
  });
});
</code></pre>

<p>To add a text search into this, we just need to add one more parameter to the <code>collection.find</code> call:</p>

<pre><code>var regexQuery = new RegExp(".*" + q + ".*");
collection.find({
  "geo.coordinates": {
    $near: [latitude, longitude]
  },
  'text': regexQuery
}
</code></pre>

<p>This makes it so simple, making it it kind of feels like cheating. Somebody else did all the hard work first.</p>

<h2>App.net Proximity</h2>

<p>This works quite well on the <a href="https://alpha-api.app.net/stream/0/posts/stream/global">App.net Global Timeline</a> but it'll really become useful once the <a href="https://github.com/appdotnet/api-spec/blob/master/resources/streams.md">streaming API is switched on</a>.</p>

<p>Of course, the <a href="https://github.com/thingsinjars/Proximity">code is all there</a>. If you want to have a go yourself, feel free.</p>
      </div>
]]></description>
<pubDate>Mon, 08 Oct 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Proximity Search</title>
<link>http://thingsinjars.com/post/465/proximity-search/</link>
<guid>http://thingsinjars.com/post/465/proximity-search/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-465">
        <p><a href="http://thingsinjars.com/post/465/proximity-search/">Proximity Search</a></p>
<p>Now that geolocated posts are beginning to show up around app.net, I found myself wondering about proximity search. Twitter <a href="https://dev.twitter.com/docs/api/1/get/geo/search">provides one themselves</a> for geotagged tweets. What a proximity search does, essentially, is provide results from a data set ordered by increasing distance from a given location. This can be further enhanced by combining it with a text search either before or after the distance sorting. This would give you a way to search for a certain query within a certain area.</p>

<p><a href="http://search.twitter.com/search.json?geocode=52.5,13.3,1000mi&amp;q=toast&amp;rpp=100">Here, for example, is a proximity search centred on Berlin including any tweet in 1000 miles containing the word 'toast'</a>.</p>

<p>When I first started thinking about the tech required for a proximity search, I remembered <a href="https://twitter.com/lukas_nowacki">Lukas Nowacki</a> back in our old <a href="http://www.whitespacers.com/">Whitespace</a> days implementing the <a href="http://en.wikipedia.org/wiki/Haversine_formula">Haversine formula</a> in MySQL (Alexander Rubin has a good overview of <a href="http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL">how to do this</a>). As much as I love my trigonometry and logarithms, I must admit, I was looking around for a simpler solution. Actually, I was looking around for a <a href="http://thingsinjars.com/post/430/copy-paste-coding/">copy-paste solution</a>, to be honest. I may even have spent some time going down that route if <a href="http://marcon.me/">Max</a> hadn't pointed me in the direction of <a href="http://www.mongodb.org/">MongoDB</a>.</p>

<p>I'd been putting off digging into NoSQL databases for a while because, well, I had no real reason to. Recently, I've either been focused on front-end dev or hacking away at Java and never really had any good reason to investigate any of these new-fangled technologies get off my lawn you kids. </p>

<h2>MongoDB</h2>

<p>After 10 minutes of messing around with Mongo, I pretty much just found myself saying “No... way. There's no way that's actually working” I'm sure those of you experience with document-oriented databases are rolling your eyes right now but for those few of us left with an entirely relational concept of databases, let me just explain it like this: you know those things you want to do with a database that are just a hassle of multiple joins and confusing references? Document databases do some of those things really really well. </p>

<p>The biggest selling point for me, however was the <a href="http://www.mongodb.org/display/DOCS/Geospatial+Indexing/">native geospatial indexing</a>. That pretty much made the majority of my proximity search complete. All I needed to do was wrap it in a nice interface and call it a day...</p>

<p>I'll follow up tomorrow with a more detailed 'How-to' guide.</p>
      </div>
]]></description>
<pubDate>Sun, 07 Oct 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>How App.net became useful</title>
<link>http://thingsinjars.com/post/464/how-appnet-became-useful/</link>
<guid>http://thingsinjars.com/post/464/how-appnet-became-useful/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-464">
        <p><a href="http://thingsinjars.com/post/464/how-appnet-became-useful/">How App.net became useful</a></p>
<p>After Twitter started announcing changes to its API usage and people started to get worried about the future of the developer eco-system, <a href="http://join.app.net/">App.net</a> appeared. It provides a streaming data-platform in much the same way Amazon provides a web hosting platform. The reason for the Twitter comparison is that one of the things you can make with it is a Twitter-like public short message system. This was, in fact, the first thing the App.net developers made to showcase the platform: <a href="http://alpha.app.net/">Alpha</a> although that example seems to have convinced many people that the whole point was to build a Twitter-clone instead of a service whose purpose is to stream small, discrete blocks of meta-tagged data. The <a href="https://github.com/appdotnet/api-spec">community-developed API spec</a> is an important aspect of App.net as well although feature discussions can devolve into musings on Computer Science theory a bit too easily.</p>

<p>For the first couple of weeks, it was fun to just hack around with the APIs, post a bit, build a little <a href="http://thelab.thingsinjars.com/appnet/">test app</a> (disabled now that more App.net clients have push notifications). It all became much more interesting, however, when two new features were added to the platform – Machine-only posts and Well-known Annotations.</p>

<h2>Machine-only posts</h2>

<p>Pretty much exactly what they sound like. These are posts that are not intended to be viewed in any human-read conversation stream. They still get pushed around the network exactly the same as all other posts but to see them, you must explicitly say 'include machine-only posts' in your API calls. For developers who have been building silly toys on Twitter for a couple of years, this is fantastic. You don't need to create a separate account purely for data transfer. This can be part of your main account's data stream. I have quite a few Twitter accounts that I just use for outputs from various applications. I have one, in fact, that does nothing but list the tracks I listen to that I created for <a href="http://thingsinjars.com/post/250/building-an-objective-c-growlview/">this side-project</a>.</p>

<p>By classifying these as <code>'machine-only'</code>, they can stay associated with the user and subject to whatever privacy controls they have set in general. This makes it far easier for the user to keep control of their data and easier for the service to track accurate usage. For devs, it also means you can hack away at stuff, even if it is to be public eventually, without worrying too much about polluting the global stream with nonsense.</p>

<h2>Well-known Annotations</h2>

<p>Annotations were part of the spec from the beginning but only implemented at the end of August. Annotation is just another word for per-post meta-data – each post has a small object attached which provides extra information. That's it. </p>

<p>The annotations can be up to 8192 bytes of valid JSON which is quite a lot of meta-data. Even with this, however, the usefulness is limited to per application use-cases until some standards start to appear. There's nothing to stop a popular application being the one to set the standard but for the more general cases, it is most fitting to continue with the community-led development model. This is where Well-known Annotations come in. </p>

<p>Well-known annotations are those attributes which are defined within the API spec. This means that the community can define a standard for 'geolocation', for example, and everyone who wants to use geolocation can use the standard to make their application's posts compatible with everybody else's. </p>

<p>Obviously, I'm quite into my geolocated data. I love a bit of map-based visualisation, I do. Here's a sample of jQuery that will create a post with a <a href="https://github.com/appdotnet/api-spec/blob/master/annotations.md#geolocation">standard geolocation annotation</a>:</p>

<pre><code>$.ajax({
  contentType: 'application/json',
  data: JSON.stringify({
    "annotations": [{
      "type": "net.app.core.geolocation",
      "value": {
        "latitude": 52.5,
        "longitude": 13.3,
        "altitude": 0,
        "horizontal_accuracy": 100,
        "vertical_accuracy": 100
      }
    }],
    machine_only: true
  }),
  dataType: 'json',
  success: function(data) {
    console.log("Non-text message posted");
  },
  error: function() {
    console.log("Non-text message failed");
  },
  processData: false,
  type: 'POST',
  url: 'https://alpha-api.app.net/stream/0/posts?access_token=USERS_OAUTH_TOKEN'
});
</code></pre>

<p>In the same way as the machine-only posts, these annotations aren't provided on a default API request, you have to specifically ask for them to be included in the returned data. This is to make sure that the majority of use cases (public streaming, human-readable conversation) don't have to download up to 8KB of unnecessary data.</p>

<h2>Retrieving both</h2>

<p><a href="https://alpha-api.app.net/stream/0/posts/stream/global?&amp;include_machine=1&amp;include_annotations=1">This is an API call to retrieve posts marked machine-only and with annotations</a></p>

<h2>Potential use cases</h2>

<p>You might have noticed, the API call above had the machine-only attribute as well as the well-known geo annotation. If I wanted to create an app that would run on my phone and track my routes throughout the day, all I would need to do would be to run that <code>$.ajax</code> call periodically with my current geolocation. The data would be saved, distributed, streamed and could be rendered onto a map or into a KML at the end of the day. I could record hiking trails or museum tours, or share my location with someone I'm supposed to be meeting so they can find out where I'm coming from and why I'm late. That's just a couple of the single-user cases. Having a shared standard means that the potential for geo-tagged posts opens up to at least equal that of Twitter's. Heatmap-density diagrams showing areas of the most activity; global and local trends; location-based gaming. Add a <code>'news'</code> annotation to geotagged posts and suddenly you've got a real-time local-news feed. Add <code>'traffic'</code> and you've got community-created traffic reports.</p>

<p>There are so many clever things you can do with location-tagged data. I hope others are just as enthused about the possibilities as I am.</p>
      </div>
]]></description>
<pubDate>Tue, 02 Oct 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>CoverMap - Nokia Maps on Facebook</title>
<link>http://thingsinjars.com/post/463/covermap---nokia-maps-on-facebook/</link>
<guid>http://thingsinjars.com/post/463/covermap---nokia-maps-on-facebook/</guid>
<description><![CDATA[
        <div class="teaser markdown" id="teaser-463">
        <p><a href="http://thingsinjars.com/post/463/covermap---nokia-maps-on-facebook/">CoverMap - Nokia Maps on Facebook</a></p>
<p>I'm almost managing to keep to my intended schedule of one map-based web experiment per week. Unfortunately, I've mostly been working on internal <a href="http://maps.nokia.com/">Nokia Maps</a> projects over the weekends recently so I've not had much to post here.</p>

<p>I can share my latest toy, though: <a href="http://covermap.me">CoverMap.me</a></p>

<p>Using just the public APIs over a couple of hours last Sunday afternoon, I made this to allow you to set a Nokia Map as your Facebook Timeline cover. The whole process is really straightforward so I thought I'd go over the main parts.</p>

<p>The exact aim of CoverMap.me is to allow the user to position a map exactly, choose from any of the available map styles and set the image as their cover image.</p>

<h2>Make a Facebook App</h2>

<p>Go to <a href="http://developers.facebook.com/apps/">developers.facebook.com/apps/</a> and click 'Create New App', fill in the basic details – name of the app, URL it will be hosted on, etc – and you're done.</p>

<h2>Facebook login</h2>

<p>I've used the Facebook JS SDK extensively over the summer for various projects but I wanted to try out the PHP one for this. Super, super simple. Really. Include the library (<a href="https://github.com/facebook/facebook-php-sdk">available here</a>), set your <code>appId</code> and <code>secret</code> and request the <code>$login_url</code>.</p>

<pre><code>$facebook-&gt;getLoginUrl(array('redirect_uri' =&gt; "http://example.com/index.php"));
</code></pre>

<p>That will give you a link which will take care of logging the user in and giving you basic access permissions and details about them.</p>

<h2>Nokia Maps JS API</h2>

<p>When I'm hacking together something quick and simple with the <a href="http://api.maps.nokia.com/">Nokia Maps API</a>, I usually use the properly awsm jQuery plugin <a href="https://github.com/mmarcon/jOVI">jOVI</a> written by the equally awsm <a href="http://marcon.me/">Max</a>. This makes 90% of the things you would want to do with a map extremely easy and if you're doing stuff advanced enough to want the extra 10%, you're probably not the type who'd want to use a jQuery plugin, anyway. Either way, you need to register on the <a href="http://api.developer.nokia.com/">Nokia developer site</a> to get your Nokia <code>app_id</code> and <code>secret</code>.</p>

<p>To create a map using jOVI, simply include the plugin in your page then run <code>.jOVI</code> on the object you want to contain the map along with starting parameters:</p>

<pre><code>$(window).on('load', function() {
  $('#mapContainer').jOVI({
    center: [38.895111, -77.036667], // Washington D.C.
    zoom: 12,           // zoom level
    behavior: true,     // map interaction
    zoomBar: true,      // zoom bar
    scaleBar: false,    // scale bar at the bottom
    overview: false,    // minimap (bottom-right)
    typeSelector: false,// normal, satellite, terrain
    positioning: true   // geolocation
  }, "APP_ID", "APP_SECRET");
});
</code></pre>

<p>This gives us a complete embedded map.</p>

<p>As I mentioned above, part of the idea for CoverMap.me was to allow the  to choose from any of the available map styles. This was an interesting oddity because the public <a href="http://api.maps.nokia.com/en/maps/intro.html">JS API</a> gives you the choice of 'Normal', 'Satellite', 'Satellite Plain' (a.k.a. no text), 'Smart' (a.k.a. grey), 'Smart Public Transport', 'Terrain' and 'Traffic' while the <a href="http://api.maps.nokia.com/en/restmaps/overview.html">RESTful Maps API</a> (the API that provides static, non-interactive map images) supports all of these <em>plus</em> options to choose each of them with big or small text <em>plus</em> a 'Night Time' mode. Because of this, I decided to go for a two-step approach where users were shown the JS-powered map to let them choose their location then they went through to the RESTful static map to allow them to choose from the larger array of static tiles.</p>

<h2>RESTful Maps</h2>

<p>The <a href="http://api.maps.nokia.com/en/restmaps/overview.html">RESTful Maps API</a> is relatively new but does provide a nice, quick map solution when you don't need any interactivity. Just set an <code>img src</code> with the query parameters you need and get back an image.</p>

<pre><code>(this should be all on one line)
http://m.nok.it/
    ?app_id=APP_ID
    &amp;token=APP_TOKEN
    &amp;nord       // Don't redirect to maps.nokia.com
    &amp;w=640      // Width
    &amp;h=480      // Height
    &amp;nodot      // Don't put a green dot in the centre
    &amp;c=38.895111, -77.036667 // Where to centre
    &amp;z=12       // Zoom level
    &amp;t=0        // Tile Style
</code></pre>

<p>That URL produces this image:</p>

<p><img src="http://m.nok.it/?app_id=_peU-uCkp-j8ovkzFGNU&token=gBoUkAMoxoqIWfxWA5DuMQ&nord&w=640&h=480&nodot&c=38.895111, -77.036667&z=12&t=0" alt="Map of Washington D.C."></p>

<h2>Upload to Facebook</h2>

<p>Given the above, we've now got an image showing a map positioned exactly where the user wants it in the tile style the user likes. We just need to make the Facebook API call to set it as Timeline Cover Image and we're done.</p>

<p>You'd think.</p>

<p>Facebook doesn't provide an API endpoint to update a user's profile image or timeline cover. It's probably a privacy thing or a security thing or something. Either way, it doesn't exist. Never fear! There's a solution!</p>

<p>With the default permissions given by a Facebook login/OAUTH token exchange/etc... (that thing we did earlier), we are allowed to upload a photo to an album. </p>

<p>The easiest way to do this is to download the map tile using cURL then repost it to Facebook. The clever way to do it would be to pipe the incoming input stream directly back out to Facebook without writing to the local file system but it would be slightly more hassle to set that up and wouldn't really make much of a difference to how it works.</p>

<pre><code>// Download from RESTful Maps
$tileUrl = "http://m.nok.it/?app_id=APP_ID&amp;token=APP_TOKEN&amp;nord&amp;w=640&amp;h=480&amp;nodot&amp;c=38.895111,%20-77.036667&amp;z=12&amp;t=0";
$ch = curl_init( $tileUrl );
$fp = fopen( $filename, 'wb' );
curl_setopt( $ch, CURLOPT_FILE, $fp );
curl_setopt( $ch, CURLOPT_HEADER, 0 );
curl_exec( $ch ); 
curl_close( $ch );
fclose( $fp );

//Upload to Facebook
$full_image_path = realpath($filename);
$args = array('message' =&gt; 'Uploaded by CoverMap.me');
$args['image'] = '@' . $full_image_path;
$data = $facebook-&gt;api("/{$album_id}/photos", 'post', $args);
</code></pre>

<p>The closest thing we can do then is to construct a Facebook link which suggests the user should set the uploaded image as their Timeline Cover:</p>

<pre><code>// $data['id'] is the image's Facebook ID 
$fb_image_link = "http://www.facebook.com/" . $username . "?preview_cover=" . $data['id'];
</code></pre>

<h2>Done</h2>

<p>There we go. Minimal development required to create a web app with very little demand on the user that gives them a Nokia Map on their Facebook profile. Not too bad for a Sunday afternoon.</p>

<p><a href="http://covermap.me">Go try it out</a> and let me know what you think.</p>

<p><p>The code is now <a href="https://github.com/thingsinjars/CoverMapMe">available on GitHub</a></p></p>
      </div>
]]></description>
<pubDate>Sat, 29 Sep 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Using CSS :target to control state</title>
<link>http://thingsinjars.com/post/462/using-css-target-to-control-state/</link>
<guid>http://thingsinjars.com/post/462/using-css-target-to-control-state/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-462">
        <p><a href="http://thingsinjars.com/post/462/using-css-target-to-control-state/">Using CSS :target to control state</a></p>
<p>There can be a fair amount of discussion provoked by the phrase "CSS only" or "Built entirely in HTML and CSS" when it comes to tech demos. The discussion generally revolves around the fact that what the phrase actually means 99% of the time is "Using CSS for the graphical bits but tracking the mouse using JS" or "Using CSS transforms for most of it but using JS to calculate the values" or any number of variations on that theme. </p>

<p>Now, I'm not saying that's a bad thing at all, I quite happily called <a href="http://thelab.thingsinjars.com/CSSKart/">my interpretation of Super Mario Kart</a> CSS-only even though without JS, Yoshi wouldn't make it to the first bend. What these demos are doing, essentially, is using CSS as the rendering layer where previously, JS would have been used. By doing so, you even get some nice hardware acceleration thrown in. Not too bad.</p>

<h2>Why fall back?</h2>
<p>The reason we fall back to JS for a lot of things is because CSS is a declarative language (see my <a href="http://thingsinjars.com/post/437/css-verification-testing/">post on CSS testing</a> to learn more). However you say things should be is how they are. In CSS, you can't set a variable to one value, do something with it then set it to a different value and do something else. For a start, you don't have variables. Even if you did, the style sheet is read top-to-bottom before anything is done with it. The variable would always have the final value assigned to it, even the first time you used it. I'm simplifying a bit but not much. If you want to do anything clever, you generally need to resort to JS, an interpreted language.</p>

<h2>Really CSS only</h2>
<p>If you want to make something properly interactive but entirely CSS, you have to find a way to modify the state of the DOM so that different sets of styles can be applied to the same sets of elements. We actually do this all the time when we change the colour of a link on :hover. The user interacts with the page, the state of the page is changed slightly, a different style applies. There's a lot you can do now that you have a way to modify the page based on user interaction. Hooray for pseudo-classes! </p>

<p>An extremely important addition to the set of pseudo-classes available in CSS3 is the :target class. This becomes set on an element when the element is the target of a clicked link. Think of in-page jump links. When you click on one and the URL changes to 'blah.html#the-thing-you-clicked', the element with <code>id="the-thing-you-clicked"</code> gets the :target pseudo-class. Now you can affect it and its children with new styles. Now it becomes interesting, you can click on something on one bit of the page and it cause something to happen on another bit of the page. </p>

<h2>Multiple-nested states</h2>
<p>By nesting several elements around the thing you're intending to modify, you can now create a set of states entirely controlled by CSS. For example, with this HTML:</p>

<pre lang="html"><code>&lt;div id=&quot;red&quot;&gt;
  &lt;div id=&quot;blue&quot;&gt;
    &lt;div id=&quot;green&quot;&gt;
      &lt;div id=&quot;yellow&quot;&gt;
          &lt;p&gt;Hello.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#red&quot;&gt;Red&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#blue&quot;&gt;Blue&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#green&quot;&gt;Green&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#yellow&quot;&gt;Yellow&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#default&quot;&gt;Default&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</code></pre>
And this CSS:
<pre lang="css"><code>p {
    color:black;
}
#red:target p {
    color:red;
}
#blue:target p {
    color:blue;
}
#green:target p {
    color:green;
}
#yellow:target p {
    color:yellow;
}</code></pre>

<p>You can change the colour of the text by clicking on the link. Without any JS.</p>

<p><a href="http://jsfiddle.net/DMNSn/">See this on JSFiddle</a>.</p>

<h2>Shiny demos</h2>
<p>This still isn't perfect. There are still going to be many things that JS is best for, calculations being one, keyboard input being another. To try and find the best way to show this off, I tried to update CSS Mario Kart to be entirely CSS and I almost got there but wasn't 100% successful.</p>
<ul>
<li><a href="http://thelab.thingsinjars.com/CSSKart/cssonly.html">CSS-only Mario Kart</a></li>
</ul>

<p>I then started to build a zoetrope in CSS, found <a href="http://andrew-hoyer.com/experiments/zoetrope/">someone else</a> had already done it and decided to modify it.</p>

<ul>
<li><a href="http://thelab.thingsinjars.com/zoetrope/index.html#spin">CSS-only Zoetrope</a></li>
</ul>

<p>Maybe soon, the phrase "CSS only" will really mean "CSS only. And a bit of HTML."</p>      </div>
]]></description>
<pubDate>Sun, 15 Jul 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Web Audio API Part 1</title>
<link>http://thingsinjars.com/post/461/web-audio-api-part-1/</link>
<guid>http://thingsinjars.com/post/461/web-audio-api-part-1/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-461">
        <p><a href="http://thingsinjars.com/post/461/web-audio-api-part-1/">Web Audio API Part 1</a></p>
I'm enjoying the chance to write for another site that I get with <a href="http://creativejs.com">creativejs.com</a> but it does leave me less time to create new posts for here. 

Having said that, there's nothing wrong with the occasional cross-post. Here's the first part of the introduction to Web Audio that I promised a couple of weeks ago:

<a href="http://creativejs.com/resources/web-audio-api-getting-started/">Web Audio API - Getting Started</a> on <a href="http://creativejs.com">CreativeJS</a>
      </div>
]]></description>
<pubDate>Tue, 19 Jun 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>CSSSquircle</title>
<link>http://thingsinjars.com/post/460/csssquircle/</link>
<guid>http://thingsinjars.com/post/460/csssquircle/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-460">
        <p><a href="http://thingsinjars.com/post/460/csssquircle/">CSSSquircle</a></p>
After a light-hearted challenge in work, I started trying to replicate a <a href="http://en.wikipedia.org/wiki/Squircle">Squircle</a> in CSS. This is a bit tricky as it can't be created using simple border-radius.

Fortunately, somebody else already did the hard work. There's a <a href="https://github.com/rdougan/nokia-meego-squircle-css">project on GitHub</a> by Robert Dougan which contains a fairly accurate squircle (good enough for screen, anyway). I decided to reproduce it reducing the number of elements used.

Here it is using pseudo-elements on a paragraph and a link tag.

<ul>
<li><a href="http://thelab.thingsinjars.com/cssquircle/">CSSSquircle</a></li>
</ul>

Now to convince the designers at <a href="http://maps.nokia.com/">work</a> to use it.      </div>
]]></description>
<pubDate>Tue, 12 Jun 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Sounds like a Hackathon</title>
<link>http://thingsinjars.com/post/459/sounds-like-a-hackathon/</link>
<guid>http://thingsinjars.com/post/459/sounds-like-a-hackathon/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-459">
        <p><a href="http://thingsinjars.com/post/459/sounds-like-a-hackathon/">Sounds like a Hackathon</a></p>
<p>A couple of weeks ago, I started digging into the <a href="http://www.w3.org/TR/webaudio/">Web Audio API</a>. Initially, I was just looking to find out what it was and see if any ideas for toys presented themselves but, kinda predictably, I ended up getting elbow-deep in a bucketful of audio routing graphs, gain nodes and impulse responses.</p>

<p>I'll write up a more detailed post about the API shortly but <a href="http://blog.marcon.me/">Max</a> and I used it quite heavily in the <a href="http://hackathon.5apps.com/">5apps hackathon</a> we attended last week and I wanted to share the outcome of our hacking.</p>

<h2>SoundScape</h2>
<p><em>&ldquo;A Nokia Map mashed together with a bunch of APIs and positional audio to create an immersive map experience.&rdquo;</em></p>

<p>For a better explanation of how SoundScape works, check out Max's slides:</p>
<ul><li><a href="http://mmarcon.github.com/slides/soundscape/">http://mmarcon.github.com/slides/soundscape/</a></li></ul>
<p>In essence, we use a <a href="http://api.maps.nokia.com/">Nokia Map</a> as the base, add on a Flying Hamster, make a call to <a href="http://www.freesound.org/docs/api/">Freesound.org</a>  for geotagged audio samples, male a call to <a href="http://www.last.fm/api">LastFM</a> for upcoming concerts, make a call to <a href="http://developers.deezer.com/api">Deezer</a> for the most popular track by the artist playing the event reported by LastFM and put them all together in the browser using <a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">3D positional audio</a>. Basically.</p>

<p>The source is <a href="https://github.com/mmarcon/htm5Hackathon
">available on GitHub</a></p>

<h2>The Actual Demo</h2>
<p><a href="http://soundscape.nodester.com">SoundScape (Web Audio API-capable browser required)</a></p>      </div>
]]></description>
<pubDate>Sat, 12 May 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Web Audio</title>
<link>http://thingsinjars.com/post/458/web-audio/</link>
<guid>http://thingsinjars.com/post/458/web-audio/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-458">
        <p><a href="http://thingsinjars.com/post/458/web-audio/">Web Audio</a></p>
<p>I'm getting a bit obsessed with the <a href="http://en.wikipedia.org/wiki/HTML5_Audio#Web_Audio_API">Web Audio API</a> just now. That's not a bad thing, of course, I just wish the <a href="http://html5test.com/compare/feature/webaudio-webaudio.html">browsers would all catch up</a>.</p>

<p><a href="http://thingsinjars.com/post/459/sounds-like-a-hackathon/">Ages ago</a>, I mentioned the <a href="http://soundscape.nodester.com/">SoundScape</a> maps mashup <a href="http://marcon.me/">Max</a> and I made at the 5apps hackathon. Finally, here's the video of the two of us presenting it at a Nokia Berlin Tech Talk.</p>

<ul>
<li><a href="https://vimeo.com/46217788">Web Audio intro and SoundScape</a></li>
</ul>

<h2>Creative tutorials</h2>
<p>This goes along with the series of <a href="http://creativejs.com/resources/">Web Audio API introductory tutorials</a> I'm writing over at <a href="http://creativejs.com">CreativeJS</a>.</p>      </div>
]]></description>
<pubDate>Mon, 23 Jul 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Web Page Screensavers</title>
<link>http://thingsinjars.com/post/457/web-page-screensavers/</link>
<guid>http://thingsinjars.com/post/457/web-page-screensavers/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-457">
        <p><a href="http://thingsinjars.com/post/457/web-page-screensavers/">Web Page Screensavers</a></p>
<p>I don't find myself using screensavers that much these days. Sure, they made sense when you needed to avoid burning a ghost of the windows start bar into your CRT monitor but with TFTs, LEDs, projectors, OLEDs and whatever else, it's rare you'll find hardware that actually needs protecting like that any more. On top of that, in my case, I'm either at my desk coding or at the coffee machine refilling. There aren't that many opportunities for me to appreciate a warp-speed starfield or some infinite pipes.</p>

<p>What I'm saying is: I miss screensavers.</p>

<p>Since I started writing for <a href="http://www.creativejs.com/">CreativeJS</a>, I've seen a lot more examples of clever, cool, pretty and downright creative demos and toys written in JS than I ever had before. You can probably figure out where I'm heading with this: these would make cool screensavers.</p>

<p>A quick bit of googling later and I found a couple of applications that let you set a web-page fullscreen as your screensaver. Of course, you can't just set any old demo as your screensaver, many of them rely on user interaction which kinda defeats the purpose.</p>

<h2>Downloads</h2>
<h3>OS X</h3>
<p><a href="http://code.google.com/p/websaver/downloads/detail?name=websaver-2.5.dmg">WebSaver</a></p>
<p>Unfortunately, this uses plain-old standard WebKit so no WebGL demos. Maybe someone can fork Chromium to make it do this.</p>
<h3>Windows</h3>
<p><a href="http://code.google.com/p/web-page-screensaver/">web-page-screensaver</a></p>
<p>This one seems to be based on IE so it probably won't work with the canvas-based demos below. If you can point me to a WebKit-based one, I'll include that instead.</p>


<h2>Old-school screensavers</h2>
<h3>Flying Windows</h3>
<p><a href="http://dl.dropbox.com/u/16145652/flying/flying.html">http://dl.dropbox.com/u/16145652/flying/flying.html</a></p>

<h3>Starfield by Chiptune</h3>
<p><a href="http://www.chiptune.com/starfield/starfield.html">http://www.chiptune.com/starfield/starfield.html</a></p>


<h2>Non-canvas</h2>
<h3>Insta-Art by me</h3>
<p><a href="http://thelab.thingsinjars.com/insta-art.html">http://thelab.thingsinjars.com/insta-art.html</a></p>

<h3>Newsola by Nick Nicholaou</h3>
<p><a href="http://www.newsola.com/#/uk">http://www.newsola.com/#/uk</a></p>

<h2>Canvas</h2>
<h3>Falling blocks by Lionel Tardy</h3>
<p><a href="http://experiments.lionel.me/blocs">http://experiments.lionel.me/blocs</a></p>

<h3>MMOSteroids by Seb Lee-Delisle</h3>
<p><a href="http://seb.ly/demos/MMOsteroids.html">http://seb.ly/demos/MMOsteroids.html</a></p>

<h3>Origami by Hakim El Hattab</h3>
<p><a href="http://hakim.se/experiments/html5/origami/">http://hakim.se/experiments/html5/origami/</a></p>

<h3>The Single Lane Superhighway by Aaron Koblin and Mr.doob</h3>
<p><a href="http://www.thesinglelanesuperhighway.com/">http://www.thesinglelanesuperhighway.com/</a></p>

<h3>Ablaze by Patrick Gunderson</h3>
<p><a href="http://theorigin.net/ablazejs/">http://theorigin.net/ablazejs/</a></p>

<h3>Visual Random by Dimitrii Pokrovskii</h3>
<p><a href="http://voxelrain.appspot.com/">http://voxelrain.appspot.com/</a></p>

<h3>Circle Worm by Ilari</h3>
<p><a href="http://style.purkki.ilric.org/projects/js_wave/">http://style.purkki.ilric.org/projects/js_wave/</a></p>

<h3>Boids by Jason Sundram</h3>
<p><a href="http://viz.runningwithdata.com/boids/">http://viz.runningwithdata.com/boids/</a></p>

<h3>3D Globe by Peter Nederlof</h3>
<p><a href="http://peterned.home.xs4all.nl/demooo/">http://peterned.home.xs4all.nl/demooo/</a></p>

<h2>WebGL Needed</h2>
<p>Just in case someone in the comments finds a WebGL-capable screensaver, here are the demos I liked that require WebGL.</p>
<h3>Clouds by Mr.doob</h3>
<p><a href="http://mrdoob.com/lab/javascript/webgl/clouds/">http://mrdoob.com/lab/javascript/webgl/clouds/</a></p>

<h3>WaterStretch by Edouard Coulon</h3>
<p><a href="http://waterstretch.ecoulon.com/">http://waterstretch.ecoulon.com/</a></p>

<h2>Further Development</h2>
<p>The ideal screensaver would allow you to enter several different URLs to allow you to easily save them. There should also be a checkbox to mark demos as 'works offline'. That way, when the screensaver starts, it checks for connectivity displays a screensaver that doesn't require a connection.</p>

<p>Add your suggestions below.</p>      </div>
]]></description>
<pubDate>Thu, 03 May 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Nokia Web Dev Blog</title>
<link>http://thingsinjars.com/post/456/nokia-web-dev-blog/</link>
<guid>http://thingsinjars.com/post/456/nokia-web-dev-blog/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-456">
        <p><a href="http://thingsinjars.com/post/456/nokia-web-dev-blog/">Nokia Web Dev Blog</a></p>
<p>Exciting news! The <a href="http://www.developer.nokia.com/Community/Blogs/blog/web-dev">Nokia Web Dev Blog</a> is finally live!</p>

<p>You might remember it was one of my <a href="http://thingsinjars.com/post/444/dun-dun-duuuuun/">2012 ToDos</a> and I can now move the To-Do to Done.</p>

<p>So far, I've put two posts up, one on using <code><a href="http://www.developer.nokia.com/Community/Blogs/blog/web-dev/2012/03/16/background-size-cover">background-size: cover</a></code> and one on quick prototyping using <a href="http://www.developer.nokia.com/Community/Blogs/blog/web-dev/2012/03/23/simple-servers">python SimpleHTTPServer</a>.</p>

<p>I'm not convinced a URL with '.../Blogs/blog/...' is necessarily the most memorable so maybe the next task would be to get something catchier. Any suggestions?</p>      </div>
]]></description>
<pubDate>Mon, 26 Mar 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Superhero Libraries</title>
<link>http://thingsinjars.com/post/455/superhero-libraries/</link>
<guid>http://thingsinjars.com/post/455/superhero-libraries/</guid>
<description><![CDATA[
        <div class="teaser " id="teaser-455">
        <p><a href="http://thingsinjars.com/post/455/superhero-libraries/">Superhero Libraries</a></p>
I'm currently writing an introduction course to JS libraries and have decided jQuery is like Batman – Objects are wrapped in a utility belt that does everything but are essentially unchanged underneath – while Prototype is more like Wolverine – Objects are injected with stuff to make them better, stronger, more deadly.

Anyone got any ideas about MooTools?      </div>
]]></description>
<pubDate>Mon, 05 Mar 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><item>
<title>Writing, writing and writing</title>
<link>http://thingsinjars.com/post/454/writing-writing-and-writing/</link>
<guid>http://thingsinjars.com/post/454/writing-writing-and-writing/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-454">
        <p><a href="http://thingsinjars.com/post/454/writing-writing-and-writing/">Writing, writing and writing</a></p>
<p>In case anybody's wondering where I've been for the last few weeks (and I know you all have), I've recently joined the <a href="http://creativejs.com/team/">CreativeJS team</a> writing about the coolest, shiniest things on the world-wide interwebs. My <a href="http://creativejs.com/2012/02/depthcam/">first post</a> went up last week.</p>

<p>I'm also about to launch the Nokia Web Dev blog (link to come soon) where I get to write tutorials about the coolest, shiniest things we do in <a href="http://maps.nokia.com/">Nokia Maps</a></p>

<p>Don't worry, there won't be fewer articles going up here than before, I just had to spend a couple of weeks figuring out which articles were best suited to where. To make up for a quiet few weeks, here's a picture of some Kohlrabi, a really tasty vegetable barely known outside Germany.</p>

<ul class="gallery"><li><a href="http://thingsinjars.com/uploaded/images/expanded/Kohlrabi.jpg" rel="lightbox[454]" title="Writing, writing and writing"><img src="http://thingsinjars.com/uploaded/images/Kohlrabi.jpg" alt="Writing, writing and writing"></a></li></ul>      </div>
]]></description>
<pubDate>Sun, 04 Mar 2012 00:00:00 GMT</pubDate>
<category>home</category>
</item><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>cssert – Like ‘assert’ but with CSS at the front</title>
<link>http://thingsinjars.com/post/438/cssert--like-assert-but-with-css-at-the-front/</link>
<guid>http://thingsinjars.com/post/438/cssert--like-assert-but-with-css-at-the-front/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-438">
        <p><a href="http://thingsinjars.com/post/438/cssert--like-assert-but-with-css-at-the-front/">cssert – Like ‘assert’ but with CSS at the front</a></p>
<p>This continues on from my post about <a href="http://thingsinjars.com/post/437/cssert---css-verification-testing/">CSS verification testing</a></p>

<p>cssert – pronounced however you feel like it – is my attempt at bringing some kind of style verification into an automated build process. If you've read <a href="http://thingsinjars.com/post/437/cssert---css-verification-testing/">the previous article</a>, you'll know that this falls into the second group of CSS test frameworks, style measurement and comparison. The system works exactly as I described above – your test files have a basic HTML structure created by traversing the DOM from the element being tested upwards. You could also include your entire HTML in the test file if you liked, it would just be unnecessary in most cases.</p>

<p>I've created a couple of (for me, at least) helpful utilities which allow these test cases to be generated from a page via a bookmarklet and then run in the browser or on the command-line. Running the tests in the browser is useful for quick human verification while the command-line interface can be integrated into an automated build system if you like that kind of thing. The test file structure is quite simple (all samples here taken from the <a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap project</a>:</p>
<p>First, we have the test file opening structure:</p>
<pre><code>&lt;!doctype html&gt;&lt;html&gt;&lt;head&gt;&lt;title&gt;cssert test page&lt;/title&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;../lib/cssert.css&quot;&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;cssert Test cases&lt;/h1&gt;&lt;p&gt;click to expand test&lt;/p&gt;&lt;script type=&quot;text/html&quot;&gt;/*==</code></pre>
<p>Then we have the name of the test:</p>
<pre><code>Intro Paragraph</code></pre>
<p>Then we have the skeleton DOM:</p>
<pre><code>&lt;!doctype html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;base href=&quot;http://twitter.github.com/bootstrap/examples/hero.html&quot;&gt;&lt;link href=&quot;../1.3.0/bootstrap.css&quot; rel=&quot;stylesheet&quot;&gt;&lt;style type=&quot;text/css&quot;&gt;
      body {
        padding-top: 60px;
      }
    &lt;/style&gt;&lt;style&gt;#cssert-style-modal {display:none;position: fixed;top: 10%;left: 50%;margin-left: -350px;width: 700px;background: #39c;color: white;padding: 10px;color: #fff;text-shadow: 0 1px 0 rgba(0,0,0,.3);background-image: -webkit-linear-gradient(-45deg, rgba(255,255,255,0), rgba(255,255,255,.1) 60%, rgba(255,255,255,0) 60%);border-radius: 5px;border: 1px solid #17a;box-shadow: inset 0 0 0 1px rgba(255,255,255,.3);}#cssert-style-modal ul,#cssert-style-modal li {margin:0;padding:0;font-size:11px;list-style:none;}#cssert-style-modal&gt;ul&gt;li {float:left;width:140px;font-size:13px;}#cssert-style-modal ul {margin-bottom:10px;}#cssert-pre {position:fixed;top:10px;right:10px;background:white;border:1px solid gray;width:200px;height:200px;overflow:auto;}#cssert-drag {position:fixed;top:210px;right:10px;background:white;border:1px solid gray;width:200px;height:20px;overflow:auto;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;container&quot;&gt;&lt;div class=&quot;hero-unit&quot;&gt;&lt;p&gt;Vestibulum id ligula porta felis euismod semper. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</code></pre>
<p>The CSS selector identifying the element to verify:</p>
<pre><code>html body div div p</code></pre>
<p>And the styles we wish to verify:</p>
<pre><code>{"font-family":"'Helvetica Neue', Helvetica, Arial, sans-serif","font-weight":"200","font-style":"normal","color":"rgb(64, 64, 64)","text-transform":"none","text-decoration":"none","letter-spacing":"normal","word-spacing":"0px","line-height":"27px","text-align":"-webkit-auto","vertical-align":"baseline","direction":"ltr"}</code></pre>
<p>A test file can contain as many test units as you like. At the very end is the close of the test file structure</p>
<pre><code>*/&lt;/script&gt;&lt;script src=&quot;../lib/cssert.js&quot;&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</code></pre>
<p>You'll probably notice the crucial bit in the test structure is the <code>base</code> element. The CSS available from the location specified here is the thing we are actually testing. In typical test lingo, the structure we have in our test file is the mock and our tests work by asserting the values &lsquo;output&rsquo; from applying the CSS to this structure are as expected.</p>

<h2>Running the tests</h2>
<h3>Running the tests in-browser</h3>
<p>Open the test page in a browser. That's it. If it's green and says 'passed', the test passed. If it's red and says 'failed', the test failed. You can see the output by clicking on the title of the test.</p>
<p>This works by loading the test file, creating an iframe and injecting the test case into the iframe as source. It then looks into the iframe and measures the styles. If they match those specified in the test file, it passes, otherwise, it fails. Clicking on the test title simply removes the <code>position:absolute</code> which is hiding the iframe.</p>
<h3>Running the tests on command-line</h3>
<p>The exact same test page can also be used with the command-line interface. cssert uses <a href="http://phantomjs.org">PhantomJS</a> to run the tests in a headless webkit instance. You'll need to install PhantomJS into your path after downloading it. Place your test case in the tests folder and run:</p>
<pre><code>$ ./cssert testcase.html</code></pre>
<p>To run all tests in the tests folder at once, simply run with no arguments:</p>
<pre><code>$ ./cssert</code></pre>
<p>This works by, again, loading the HTML from the test files. In this case, the structure is injected into a new headless browser window. The styles are measured and the output is redirected to stdout. Each browser window test is also rendered as a PNG so you can see what failed if any did.</p>

<h2>Limitations</h2>
<p>I'm not saying this is the ultimate solution to CSS testing. Declarative languages don't sit well with testing. This is as close as I can get for the moment. I'm also not going to be able to head off or counter all possible complaints or criticisms but I will cover a couple.</p>
<p>Firstly, most of the limitations you'll run into are caused by using the automatically generated tests. They're good for creating a starting point but at the moment, they need to be tweaked for many cases.</p>
<h3>Sibling selectors</h3>
<p>Because the test generates the DOM via following parents up the structure, sibling elements are ignored. These styles are still testable, though. Simply add the sibling element into your HTML test block.</p>
<h3>Styles modified by JS</h3>
<p>The styles are measured on the element as it is when the case is generated. The test compares this against the styles provided by the CSS. If the element contains JS-only styles not added by CSS, they will not be correctly matched. Modify your test case to allow for this.</p>
<h3>Why not use Selenium?</h3>
<p>This, essentially does the same as Selenium would do if you took the time to set up your test cases. This makes it much easier to set up test cases, though.</p>
<h3>@font-face!</h3>
<p>If your @font-face declaration contains a suggested 'local' source (as recommended in Paul Irish's <a href="http://paulirish.com/2009/bulletproof-font-face-implementation-syntax/">bulletproof syntax</a>), a <a href="https://bugs.webkit.org/show_bug.cgi?id=36351">bug in QTWebkit</a> will prevent the test case from running correctly.</p>

<h2>Installation</h2>
<p>Just clone the git project from <code>git@github.com:thingsinjars/cssert.git</code> and you're good to go.</p>
<p>The tests directory comes with some sample tests generated using Twitter's Bootstrap project. Put your tests in that same place.</p>      </div>
]]></description>
<pubDate>Mon, 28 Nov 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>A collection of bookmarklets</title>
<link>http://thingsinjars.com/post/415/a-collection-of-bookmarklets/</link>
<guid>http://thingsinjars.com/post/415/a-collection-of-bookmarklets/</guid>
<description><![CDATA[
        <div class="teaser html" id="teaser-415">
        <p><a href="http://thingsinjars.com/post/415/a-collection-of-bookmarklets/">A collection of bookmarklets</a></p>
<p>Bookmarklets are the handiest little things. In case you don't know (which I'm sure you do), they're small chunks of JS that you store in your browser's Bookmarks or Favourites section which you can launch while looking at any web page. I write bookmarklets for all kinds of different tasks &ndash; navigating quickly around the build monitor at work, filling in tricky forms that my browser autocomplete doesn't handle, etc. </p>

<p>Here are a few of bookmarklets I find extremely useful for web development. To add them to your browser, simply drag the link on the title into your bookmark bar, hold shift down and drag or right-click and 'Add to Favourites', depending on what browser you're in.</p>

<h2><a title="Add Script" href="javascript:(function(){document.body.appendChild(document.createElement('script')).src=prompt('Script to add');})();">Add JS to the page by URL</a></h2>
<p>This will allow you to add any script you like to the current page. This can be particularly useful if you want to add a certain library or plugin to a page to investigate it further.</p>
<pre><code>javascript:(function(){document.body.appendChild(document.createElement('script')).src=prompt('Script to add');})();</code></pre>

<h2><a title="Add jQuery" href="javascript:(function(){document.body.appendChild(document.createElement('script')).src='http://code.jquery.com/jquery-latest.min.js'})();">Add the latest CDN jQuery to the page</a></h2>
<p>A variation on the above bookmarklet, this simply adds the latest version of jQuery. If you want to be able to play with a page and are familiar with jQuery, this will ensure that it is loaded and attached.</p>
<pre><code>javascript:(function(){document.body.appendChild(document.createElement('script')).src='http://code.jquery.com/jquery-latest.min.js'})();</code></pre>

<h2><a title="Add CSS" href="javascript:(function(d){if(d.createStyleSheet)%20{d.createStyleSheet(%20u%20);}%20else%20{var%20css=d.createElement(%27style%27),u=prompt(%27CSS%20to%20add%27);css.setAttribute(%22type%22,%22text/css%22);css.appendChild(document.createTextNode(%22@import%20url(%22+u+%22)%22));d.getElementsByTagName(%22head%22)[0].appendChild(css);}}(document))">Add CSS to the page by URL</a></h2>
<p>Add any stylesheet to the current page with a particular URL. This is handy if you want to demo variations to clients, I find. particularly if you predefine the CSS URL.</p>
<pre><code>javascript:(function(d){if(d.createStyleSheet)%20{d.createStyleSheet(%20u%20);}%20else%20{var%20css=d.createElement(%27style%27),u=prompt(%27CSS%20to%20add%27);css.setAttribute(%22type%22,%22text/css%22);css.appendChild(document.createTextNode(%22@import%20url(%22+u+%22)%22));d.getElementsByTagName(%22head%22)[0].appendChild(css);}}(document))</code></pre>



<h2><a title="Submit to a specific reddit" href="javascript:window.location=%22http://www.reddit.com/r/webdev/submit?url=%22+encodeURIComponent(window.location)+'&title='+encodeURIComponent(document.title);void(0);">Submit this page to the webdev subreddit</a></h2>
<p>This isn't so much a web dev helper, more a general helper. I use this (or a variation thereof) to submit posts to specific <a href="http://www.reddit.com/">reddits</a> with fields prefilled. This bookmarklet defaults to the <a href="http://www.reddit.com/r/webdev/">webdev</a> subreddit.</p>
<pre><code>javascript:window.location=%22http://www.reddit.com/r/webdev/submit?url=%22+encodeURIComponent(window.location)+&#x27;&amp;title=&#x27;+encodeURIComponent(document.title);void(0);</code></pre>

<h2><a href="javascript:(function(){var div = document.createElement('div'); div.innerHTML ='xstyle' +prompt('Style to add')+ '/style';document.body.appendChild(div.lastChild);})();">Add a CSS rule to the page</a></h2>
<p>I can't remember whether I wrote this one or if I found it somewhere. The 'x&lt;style&gt;' is something from the middle of jQuery, though. Anyhow.</p>
<p>This allows you to add a style block directly into the page. This is useful for small CSS injections where the browser's web inspector is unavailable or incapable. Even though it's a single prompt that pops up, there's no reason why you can't past an entire stylesheet in there. I sometimes find myself doing that when I'm previewing designs on a production server.</p>
<pre><code>javascript:(function(){var div = document.createElement(&#x27;div&#x27;); div.innerHTML =&#x27;x&lt;style&gt;&#x27; +prompt(&#x27;Style to add&#x27;)+ &#x27;&lt;/style&gt;&#x27;;document.body.appendChild(div.lastChild);})();</code></pre>      </div>
]]></description>
<pubDate>Mon, 28 May 2012 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></channel>
</rss>