Skip to content

“Mr. Penumbra’s 24-Hour Bookstore” by Robin Sloan

Mr. Penumbra's 24-Hour BookstoreMr. Penumbra’s 24-Hour Bookstore by Robin Sloan
My rating: 3 of 5 stars

Mr. Penumbra’s 24-Hour Bookstore is an adventure story laden with geek references and an eclectic mix of characters, in which our unsuspecting hero picks up a night shift at a bookstore, through which he meets a few odd customers who lead him to discover an ancient secret society and a code-breaking puzzle that promises the answer to eternal life.

There is an intentional contrasting of the old-and-paper-based versus the new-and-technology-based. This is mostly framed from the perspective of the young, tech-savvy protagonist, so presents the paper-proponents as antiquated Luddites. There is the odd occasion that paper triumphs and the technology geniuses are proven fallible, but you can definitely detect the author’s bias ūüôā

I found some of the references to technology to be a bit awkward and simplistic. I was also a bit put off by the huge amount of fawning over Google, without mention of nearly any of the other technology companies located in the Silicon Valley setting. This book is close to challenging The Internship in terms of most gratuitous use of Google in a story; luckily the rest of the book is good enough to excuse this, which is not the case with the aforementioned film!

Overall, this is very well written and a compelling enough mystery to make you want to read just a bit more. The story of infiltrating a secret society with the aim of eternal life is less than original, but the framing within the modern era and the slightly unexpected resolution gives Mr. Penumbra’s 24-Hour Bookstore enough freshness to make it an enjoyable read.

View all my reviews


“Stardust” by Neil Gaiman

StardustStardust by Neil Gaiman

My rating: 3 of 5 stars

Stardust is a fantasy adventure coming-of-age story about a teenage boy who travels into the mystical land beyond the wall to fetch a fallen star for the woman he loves.

This story is short and concise, but still conveys an epic adventure across many lands and many encounters. While we mostly follow the main character, Tristran Thorn, the doings of three other main antagonists (as well as a few others) are woven into the story.

Of course, this book has been made into a Hollywood movie, which I saw long before reading this, so a comparison is worthwhile. I was surprised by how closely the movie had followed the plot of the book. There were a couple of sections that the film omitted, though were no great loss. I did prefer the movie’s tretment of the lightning ship, but I’m undecided whether I liked the book’s technicality-resolved ending over the film’s action-packed finale.

A great story, but I think I would recommend the movie’s telling of it, as it has a little more meat in the right places.

View all my reviews

“The Psychopath Test” by Jon Ronson

The Psychopath Test: A Journey Through the Madness IndustryThe Psychopath Test: A Journey Through the Madness Industry by Jon Ronson

My rating: 4 of 5 stars

In The Psychopath Test, Jon Ronson takes us on yet another adventure trough an area of society that we may only vaguely have heard of and has us forming strong opinions and then opposing ones within hours!

The Psychopath Test follows a very similar format to Them and The Men Who Stare at Goats: the general subject is introduced through a mystery, a character is introduced that will be referred back to at various points throughout the book, the entire area is explored through Therouxian interviews and well-researched profiles, a diversion into something that doesn’t feel like it entirely fits in this book, before concluding that, after all that, maybe we’ve been thinking too hard about finding an absolute answer and the reality is a bit greyer than we’d like to think.

Despite that rather cynical portrayal of Ronson’s style, this book is a very good read, perhaps my favourite of the three. Ronson’s writing has matured significantly and the narrative flows almost entirely unhindered in this outing. I was most surprised at the conclusion this book built to, and it was a shame that the pharmaceutical-and-lobbyist angle wasn’t given more space. Maybe he’s saving that for another book?

If you’re a fan of Ronson’s previous books, definitely pick this up. If you’ve not read any of them, start with this. His persona and interview style is reminiscent of Louis Theroux, so the book is subtly entertaining throughout, and everything else he writes is thoroughly researched and well explained. Go read it!

View all my reviews

“The Men Who Stare at Goats” by Jon Ronson

The Men Who Stare at GoatsThe Men Who Stare at Goats by Jon Ronson

My rating: 4 of 5 stars

The Men Who Stare at Goats is a broad examination of the US use of New Age-inspired approaches to warfare, right from its post-Vietnam, 1960s-Californian roots through to it’s influence on techniques used in the War on Terror.

Ronson continues his investigations into events and reported activities that regularly get swept under the conspiracy theory carpet. Somehow Ronson presents a side of the argument that seems to give these theories credence, though I expect it’s more a matter of Ronson being unsure himself and reporting what he discovers. Unfortunately, there is rarely any hard evidence, merely stories told by people who claim to have been there.

In The Men Who Stare at Goats, the history of New Age techniques is presented by a mix between descriptions of what happened (largely sourced from other books) and interviews with people who served in the US Army special forces when these techniques were experimented with. There are a few side stories that fit into the narrative, as the ideas leaked out to other governmental agencies and even a few civilians who exploited opportunities to train people in these techniques.

This book is a fascinating, but slightly troubling look at the US approach to defence. While you could dismiss it as little more than rumour and hearsay, it would be worrying to not question why when seemingly presented with an approach to more peaceful encounters with enemy forces the only thing that stuck was how to torture prisoners in more creative ways. Worth reading.

View all my reviews

“Them: Adventures with Extremists” by Jon Ronson

Them: Adventures with ExtremistsThem: Adventures with Extremists by Jon Ronson

My rating: 4 of 5 stars

Them is Jon Ronson’s exploration of the groups of the world that believe that there is some form of shadowy cabal that secretly runs the world. These are the folks that most would dismiss as crazy, paranoid conspiracy theorists, but Ronson gives them a voice and it makes for fascinating reading.

Ronson’s style is a little disjointed, sometimes jumping to recount a story that is not entirely clearly connected to the previous. Thematically though it largely hangs together to form a coherent story. The emphasis is on the existence of the Bilderberg group, but we also get introduced to rival Klan leaders, a British Muslim funding war overseas, David Icke and Dr Ian Paisley. Amazingly, Ronson bases his writing on interviews or adventures with all of these, rather than second hand reporting, which makes the book all the more compelling.

I think Ronson could have tied things together a little better, and perhaps better made the point I think he was aiming for: lots of groups with radically opposed ideologies think there’s a self-appointed secret world power, suggesting that if they perhaps put aside their differences and worked together they might find evidence to convince the rest of the world. However, I think he also touches on the reality that the activities that these groups perceive as secretive manipulation are actually just glimpses of the political equivalent of the extra-curricular activities those in any other profession would partake in. This is best demonstrated in the grand finale when Ronson attempts to infiltrate and view the owl-burning ceremony that takes place at Bohemian Grove.

Them is definitely a set of interesting stories, that will make you consider the workings of global politics and business from a slightly different perspective. The narrative could flow a little better, but it is written well enough for this not to be jarring. If conspiracy theories intrigue you at all, you will enjoy reading Them.

View all my reviews


Slaughterhouse-FiveSlaughterhouse-Five by Kurt Vonnegut

My rating: 3 of 5 stars

This is a difficult story to decipher, but I think that was thematically intentional. Slaughterhouse-Five is a novel that purports to be about the fire bombing of Dresden in the Second World War, but very rarely addresses the issue directly. It skirts around this kernel through the mechanic of the protagonist becoming “unstuck in time”: in essence, his mind wanders to reliving events that have already happened or are yet to happen. Combine this with a sprinkling of alien abduction and you’ve got a story that leaps from the sombre to the surreal in a matter of sentences.

It is the context of this non-linear narrative that explains the lack of cohesion; in trying to tell the story of the Dresden fire bombing, the narrator tells us about everything else. This approach, I am fairly certain, is intended to mimic the conversational style, and perhaps even thought processes, of individuals that lived through and participated in such attrocities. It may even be reflective of what we now call post-traumatic stress disorder (PTSD), an affliction little recognised until many years after the great conflicts of the 20th Century.

As a novel, Slaughterhouse-Five read very quickly. This made it felt short, but there was no lack of story here. The language used is very short and quite simple (in the most part). In fact at one point I read a section of conversation out loud and I couldn’t help but feel it sounded like I was reading a children’s book (though maybe that’s the only time I practice reading books out loud!) This is not a criticism, just an observation as to why I read it so quickly. It perhaps also represents the everyday man that was sent to war, deliberately contrasting them with the highly educated and verbose politicians who decided to send them?

While Slaughterhouse-Five didn’t move me as deeply as perhaps it should have, it is very readable and gives excellent insight into the darkest side of a war that many of us are too many generations away from to know about. I expect I’ll read it again at some point, to better understand it.

View all my reviews

Research grants yield Twitter followers?

I went to a nice little event on Monday evening, organised by the guys at the University of Southampton. Effectively the aim was to coerce some people with ideas and people with having skills to build some little tools, applications and visualisations using data gathered about institutions under the second-level domain (largely UK universities, entities related to research or other academic pursuits).

I personally had a really rewarding time for a number of reasons. A handful of our first year undergraduates (from a class I teach called “Space Cadets“) attended, contributed and seemed to enjoy themselves. I also learned about the research topic of one of our new PhD students (Johanna) and was impressed at how pertinent and insightful her topic is, and at how she was using this event as a way to gather preliminary data. I also got to catch up with some friends I haven’t seen for a while, like Marja and Colin. And all this while almost hacking something together!

Full disclosure, we didn’t quite finish what we aimed to do within the time, but I managed to pull it together in the pub afterwards ūüôā
Gateway to Research homepage
So what did we do? Well we started off looking at the data on Gateway to Research, as we were going to see if we could link it to news stories on university RSS feeds (do universities publish many stories about their research?). Organically, this evolved into looking at their Twitter feed instead (as the Observatory already scrapes the Twitter account from homepages). As a simple goal, we wondered if there’s any observable link between number of Twitter followers and number of research grants granted.

By the end of session we’d just about extracted all the relevant data (name of university, Twitter account, followers and number of research grants – 4 bits of data from 4 independent data sources) and displayed it as a list. We were somewhat hampered by my poor decision to attempt this in Javascript, as the Same Origin policy made it impossible to AJAX data from live APIs (why make your data available in JSON then not allow me to access it in Javascript, I say)*. However, a quick rewrite into PHP got us back on track.

As I said, we weren’t quite done, as I wanted to visualise this data somehow, as well as fix a few bugs. In the pub, I tried to make use of the (unfortunately deprecated) Google Image Chart API, but it was capping at some weird values. To resolve this, I outputted the data as CSV and imported into Google Sheets and generated the graph manually (hack events require cutting some corners and thinking on your feet!) This is what we got:

grants vs followers

This is the number of research grants a university has had funded against number of Twitter followers on the first Twitter account on their homepage. It’s on a log scale.

The grants vs followers data in a Google spreadsheet, in case you want to look.

What does it tell us? Well it says that the more successful research universities also have more people listening to them on social media. Is this what we would have guessed anyway? It’s easy to say yes in hindsight, but it’s nice to have some numbers to support it. Of course, I’ve not yet run the correlation to see if this is a significant relationship; that’ll come with a bit more time.

Perhaps more importantly, it has helped us identify some quirks in the data and the nuances of how to handle it. For example, the Observatory will record all Twitter handles referenced on the homepage. If there’s a widget displaying a Twitter feed on the homepage, it will include all accounts @replied and retweeted. It also stores the date of an observation as the name of a property in an object, which are hard to sort, so it’s difficult to get latest observation (clearly this requires a smidgen of preprocessing). We spotted these by delving into a couple of the outliers, and interestingly by cleaning up the data, it moved them closer to the centre of the cluster of points.

To conclude, the event was a great success. I think the 2-hour hack might be the perfect format for exploratory data hacks. It’s demoralising to spend a day or three hacking and have nothing to show for it; spending an hour or three and having a result (even a small one) is massively rewarding. I hope to tidy up this code, check the details of the data (especially what grants GtR includes) and do some stats on it. We’ve observed there’s some link (though no inference about the cause of that link) between research funding and social media popularity of universities. I became a bit more confident in having with data within a time constraint, and had fun doing it!


* I realise now that what I needed was JSONP. Unfortunately, GtR doesn’t support that anyway. I could have used a JSON proxy (e.g. JSONProxy or written my own in PHP) but I didn’t think of that until the day after the hack! At learning has happened ūüôā

New Year’s Day 2015 parkrun double finder

I got a comment on¬†the¬†post about my NYD double finder from last year asking whether I was going to do one for this year. This inspired me to run the code again, and it seems to have worked. There’s now a list of parkrun doubles that are (just about) feasible to¬†do on¬†1st January 2015:

parkrun double finder NYD 2015

Please be aware that it may be physically impossible or unsafe for you to attempt some of these doubles. A double is included in the list, if the second parkrun is 13 minutes plus a Google-estimated driving time. This means you’d have to run a world record 5km, and hit no traffic on the drive to the next one.

Therefore, please check whether the double you want to do is realistic. Work out roughly how long you think you’ll take to run the first parkrun, then allow¬†time to get your breath back, get barcode scanned, walk to your car and drive safely to the next double.

If this is useful to you, or you think there‚Äôs a possible double missing, or you have any other feedback, please comment below. I love to hear back from anyone who makes use of this ūüôā

Rendering template with array of data in SammyJS

In my first play around with SammyJS, I was severely restricted for time, so just had to hack it to work. However, there were a couple of things I couldn’t work out how to do that bothered me, so I thought I’d figure out what was going on, and maybe try to fix anything that’s broken (be it buggy code, or lacking documentation).

My main concern was that, after having added things to the DOM using SammyJS, I couldn’t seem to select those things using jQuery. I was also concerned that if I ran the same loop twice (to print different bits of the array) the output was unintentionally interleaved. Finally, I couldn’t really get my head around how to insert some HTML into the DOM, then perform my main loop. It turns out these were a all a little interrelated ūüôā

What I Was Doing

In my initial hack, I had a number of routes that looked a bit like this:

this.get('#/drunkbeers', function(context) {'');

	context.render('browse-header.template', {category: 'Drunk Beers'}).appendTo(context.$element());


	// Display drunk
	$.each(this.items, function(i, item) {
		if(localStorage['_drunk'] == "true") {
			var id =;
			var wantclass = 'btn-default';
			if(localStorage[id+'_want'] == "true")
				wantclass = 'btn-primary';

			var drunkclass = 'btn-default';
			if(localStorage[id+'_drunk'] == "true")
				drunkclass = 'btn-success';

			var unavailableclass = 'btn-default';
			if(localStorage[id+'_unavailable'] == "true")
				unavailableclass = 'btn-warning';

			var notes = localStorage[id+'_notes'];
			if(notes == undefined) notes = "";

			context.render('beer.template', {beer: item, wantclass: wantclass, drunkclass: drunkclass, unavailableclass: unavailableclass, notes: notes})


This first uses two very simple templates to render some header information, then iterates over all the items in an array (loaded elsewhere from a JSON file), and if that item is marked as “drunk”, in localStorage, it renders¬†that item using a template. Some issues here are that if I code¬†a jQuery select after the iteration, it doesn’t find any of the things added to the DOM, and because I used $.each() to go through all the items in the array, I can’t use .then() afterwards to¬†force ordering on the actions, which I believe is what was causing the interleaving of two array outputs.

How to use renderEach()

In my investigations for how to do this right, I was¬†noticed that example on the front page and its line this.load('posts.json').renderEach('post.mustache').swap(); The important thing here is renderEach(), which we assume is probably rendering the template post.mustache for every item in posts.json. But what if we’ve already loaded posts.json and stored in a variable (as recommended in the tutorial)? SammyJS certainly doesn’t attach .renderEach() to the Array prototype (though maybe it should?)

Let’s take a look at the documentation for renderEach():

sammyjs - renderEach documentation


Well, the example sort of makes sense. Run renderEach(template_location, array_of_data) and it will render the template for each item in the array. But that doesn’t sync with the arguments listed. What is name for? And why isn’t it passed in the examples?

Also, what about that this.load('posts.json').renderEach('post.mustache')? How does it get the data when nothing is passed as the 2nd nor 3rd argument? And what if your array isn’t associative: what variable name is each item put in (important for referring to in the template)?

Previous Data

It turns out, that whenever you call one of these functions in a RenderContext, it pushes the results from the previous function out of the content property and into the previous_content property. If data is not set, and previous_content is an array, then it will use previous_content in .renderEach(). This is how the this.load('posts.json') gets into .renderEach().

Reference Variable Name

If the array (either from previous_content or data) is just pure values (e.g. [“pete”, 15, true, “hey”, “there”, 22]) then it’s unclear what variable name this will be passed in as to the templating engine, so it will be hard to refer to this value in the template. If this is the case, .renderEach() lets you provide a string name for this variable, in the 2nd argument, name. If you set this, make sure you use the same name as in your template ūüôā

Order of Arguments

If your array already has a key for each value (e.g. because it’s an array of objects – [{x: “pete”}, {x: 15}, {x: true}, {x: “hey”}, {x: “there”}, {x: 22}]), then you may omit the name argument. SammyJS detects this (because argument 2 is now an array, instead of a string), and shifts all the arguments along one. It’s times like these that you wish JavaScript had named parameters!

Updated DOM

Interestingly, now that we’re using .renderEach() to render the items of the array, instead of $.each(), it means we can tag a .then() on the end. Now, inside the callback provided to .then(), the DOM is up-to-date and any jQuery select you perform will work. Hooray!

Also, there seems to be another way to at least attach event handlers to the dynamically added elements, called event delegation:

$('#main').on('click', 'li', function() {

However, this doesn’t really work for other jQuery actions (not really sure why), so it’s easier to just use .then() where possible.

Printing to Document

Using templates is excellent for situations where you need to repeat the same format of information lots of times, but when you just want to print a line of HTML, it’s a bit laborious. However, when you realise that this.$element() (or context.$element(), not sure which is more appropriate when), works just like the jQuery function $, and therefore you can call regular jQuery functions, such as .append(), it becomes a little easier:

context.$element().append('<a href="#">bob</a><ul></ul>');

Confusingly,¬†you can’t use .then() after this, because it’s a jQuery function. However, it seems you don’t need to, presumably as this has its effect and returns immediately (whereas the¬†rendering operations must work asynchronously).


I made an amendment to the documentation of EventContext.renderEach(), and submitted a pull request, so hopefully this very powerful function will be a little clearer to future users (if it gets accepted and merged in)!


What were the main things I’ve learned here?

  • You can treat this.$element or context.$element like $ or jQuery (use it to select things).
  • .renderEach() is tricksy but powerful once you understand what the arguments do!
  • If you’re generating parts of the DOM through SammyJS rendering, you must use .then() to ensure your code sees the latest¬†version of the DOM, else¬†your jQuery selections may occur before the rendering has completed.

Offline mobile web app with SammyJS

Last week I went to the Great British Beer Festival ( and to help me track the beers I wanted from the 900 or so draught and bottle beers and ciders available, I built a little web app.

The GBBF beer selector doesn't really work on mobile...

The GBBF beer selector doesn’t really work on mobile…

Great British Beer Festival do provide a beer selector on their website, but much like most organisations who make a web-thing for marketing, they’ve completely missed the point: people want to peruse the list while they’re *at* the beer festival, and their site is rather unfriendly to use on smartphones. What is needed is a mobile web app.

Last year a few of us had a go at this. My approach was to build a jQuery bookmarklet on top of their beer list, to allow the user to mark beers as “wanted”, “drunk” and “unavailable”. The advantage of the bookmarklet approach was that I didn’t have to make a copy of their data (and all the IP issues that incurs), and I was just augmenting what was already there (so hopefully would be less work). The disadvantage was that it required me to be online to access their website, and the jQuery to filter through their rather div-heavy DOM was slow on my Nexus One!

This year my aim was to build a small, simple web app in as few files as possible, so that I could download it onto my phone and use it offline (i.e. in airplane mode). This would involve getting the data to store in the web app (I have a lot of screen-scraping PHP code already) and then building a single page web app to let the user browse the beers and mark them as “wanted”, “drunk”, “unavailable” and make notes.

Getting the data

Unfortunately, the Great British Beer Festival are not an open data company (other than accidentally leaving an Excel of the real ales on their site). This means I had to screen-scrape the website. I’ve done a lot of this in some other projects, so just adapted the PHP code I already had. This involved reading every row of the table on the GBBF site into an associative array, then spitting it back out as JSON ready to be loaded into my JavaScript web app.

This took 3 or so hours the night before I was meant to be going to the beer festival. I was running out of time, but I intentionally wanted to restrict how long I could spend on this ūüôā I went to bed and decided to do the front end of the web app in the morning.

Single Page App framework

Despite¬†never having built an offline web app, I knew I’d¬†need a framework to handle the displaying of different “pages”,¬†because there will in fact only be one web page. There are a bunch out there, but I wanted something that I could quickly pick up and build something with in about 3 hours: that significantly reduces the field! One thing that annoys me about software frameworks is how ridiculously complicated they are to start with. You typically have to read several days worth of tutorials, which explain in excruciating detail all the quirks and inconsistencies of that framework (as if you’re going to remember any of it)!

Basically all you need for a simple client-side web app!

SammyJS Hello, World: Basically all you need for a simple client-side web app!

With PHP I spent a while trying Zend, CodeIgniter and CakePHP, all of which suffer from this flaw, before stumbling upon FatFreeFramework (F3), which is now my PHP framework of choice. I’ve recently been learning Django, which is a little bit heavy, but I’ve not investigated simpler frameworks yet (though I hear that it’s probably flask or bottle). Now was the time to find one for JavaScript.¬†My initial searches brought up things like AngularJS, EmberJS and BackboneJS, but as always the ones people shout about most are the ones they spend 40 hours a week working with in their job, so they know all the ins and outs. Eventually I found SammyJS, which had a Hello, World of only 9 lines of code, on its homepage, which instantly showed that it did everything I needed: handle a GET request, load data from a JSON, and render all items with a template. Perfect!

I first followed the first part of the SammyJS tutorial, which walks through loading from JSON, displaying items using templates, and then displaying other pages. I implemented what I was reading, but using my data rather than their example data. This quickly got me a base for what I needed: listing all the beers that are available.

I then added the ability to search by style. This was just the code for displaying all the beers, with an if statement to only display ones of a chosen style. Which style was defined by a URL route parameter. After repeating this for country, I realised that the code is the same for bar, brewery, country and style, so I created a JSON file for each of these and generalised the code to load the JSON file for whichever category is in the URL.

I wanted to make it look not-too-terrible, so went to put in jQuery Mobile to make it really look like a¬†mobile app. However, when I added it in, it started constantly reloading the root of the web server! It turns out that jQuery Mobile is more than just a set of widgets, it is also a framework for¬†single-page apps (if only I’d known)! Anyway, that broke everything, so I immediately got rid of it and dropped in Bootstrap, so I could give the lists of links and buttons a more user-friendly look and feel.

Finally, I had to add the functionality for letting the user select which beers they want to try, have drunk and any notes they want to make. I had written most of this last year, using jQuery and HTML5 localStorage, so it should have been a pretty easy job to port it over. However, SammyJS doesn’t seem to let you use regular jQuery, which is a bit of a pain. I ended up using regular onclick and onblur attributes in the HTML to call functions I defined in my JavaScript. This got the job done, but it was a bit disappointing to not be able to attach the events programmatically.

While I’m on the subject, HTML5 localStorage is really lovely. It is so much nicer to use than cookies, and just involves reading and writing values in an object that acts like an associative array called localStorage, and that gets magically saved by the browser between visits to the page. Simple!

I ran into another peculiarity of SammyJS when trying to display wanted beers as a separate list from unwanted beers, on the same page. I tried duplicating the loop, just with a different if statement in each. However, this still displayed some of the unwanted beers interleaved with the wanted beers. I think this is because some of the actions in SammyJS are based on asynchronous tasks (like loading a JSON file), so you’re meant to chain them using .next(). However, some of the SammyJS functions don’t seem to return an object that has .next(), so I was unable to chain in the way I wanted. A related problem meant that I found it difficult to insert text into the page before loading the JSON file. I’m sure I can figure out how to fix both these problems, I just didn’t have the time to do so during¬†the development of this app!

The last thing I did before running out the door to get the train to London was to put it online and test it briefly on my smartphone. It looked like it worked, and the only thing I needed to tweak was the CSS to increase the size of the text a little and set the viewport width.

<meta name="viewport" content="width=device-width, initial-scale=1">

Webserver on my phone

A web server on your Android phone!

A web server on your Android phone!

On the train, I tested whether I could save the app and use it offline. My very quick search indicated that in Android you could save a bookmark to the home screen for offline use. This did not work. I’d hoped that the (almost) single file aspect would mean Chrome would easily cache it and give me access to it, but as soon as I turned on airplane mode, Chrome immediately refused to even load any page (because it’s offline)!

I tried downloading all the files from the web server (luckily I had left a zip of the directory on the server), and using the file:/// protocol but this seemed to stop any of the JavaScript working.

My final chance was to download a web server to run on my phone and host the files locally.¬†There is a web server called kWS on the Play Store, which is free and did exactly what I needed! It’s also one of the few apps I’ve ever installed that wanted permission to access only 2 things (files and network, obviously for a web server). Once setup, with the files in /sdcard/htdocs/, I could access my app at localhost:8080. Brilliant!

Offline App Cache

The palaver with having to host a web server on my phone got me thinking: given a settings file at a certain location relative to the web app (say app.offline in the same directory as the home page), I could build an app that downloads all the appropriate files, and then hosts them locally on a web server on the phone. This seemed a little overkill, as someone must have thought of this before, so I hunted around a little.

And of course this is already a solved problem! I first found an Adobe blog about taking web apps offline, and once I knew the name of the technique (“app cache manifest”) I managed to find an HTML5rocks¬†application cache tutorial which explained a few of the nuances and an offline HTML5 tutorial that explained some of the tricks to debugging. It’s dead easy: create a manifest file which lists the files that are required offline (in my case index.html, app.js and a few .json data files) and reference it in the <html> tag of your pages. The only downside is that you do have to manually list every file you want offline (wildcards don’t really work – it can if you have directory listing switched on, but it didn’t work for me), but you could write a server side script to generate this if you have lots of files.

It’s quite useful to know that in Chrome you can go to¬†chrome://appcache-internals/ to see whether your app has been cached, and to clear the cache after you’ve updated your app. The console in Chrome Inspector is also helpful, as it tells you each of the files it is caching, and if it fails at any of them, gives you an error message.


There we go. In less than a day’s work I managed to¬†learn a client-side app framework, build an app to meet my needs and figure out how to get it to work offline. Hopefully, this will be useful practice for future app development! Of course, some of this has built on previous skills I have learned (PHP web site scraping,¬†jQuery and localStorage), but I’m glad¬†I managed to¬†find the tools to use quite easily, wrangle them into what I wanted and have the chance to share those tools here!

SammyJS is pretty lovely. Unfortunately it seems to become a bit of a pain to do things that don’t fit exactly in its view of the world, but it does do those basics elegantly enough that I’d like to use it again. localStorage is brilliant for storing simple information between uses of the app. The application cache is such an easy way to save your app offline and keep using it when not connected to a network. The bits for building offline web apps are all there, and they’re really easy to pick up. My advice is to start with these, and learn something more complex when you need it.

My code is at¬† in case you want to check it out (note you’ll need to get SammyJS as I’ve not figured out the licensing yet). You can check out a working version of it here:¬†