Longform
Tip: using Pandoc to create truly standalone HTML files
If you’re using the excellent Pandoc to convert between different document formats, and you:
- want your final output to be in HTML;
- want the HTML to be styled with CSS;
- and want the HTML document to be truly standalone;
then read on.
The most common approach with Pandoc is, I think, to write in Markdown, and then convert the output to RTF, PDF or HTML. There are all sorts of more advanced options too; but here we are only concerned with HTML.
The pandoc command has an option which allows you to style the resulting HTML with CSS. Example 3 in the User’s Guide shows how you do this, with the -c option. The example also uses the -s option, which means that we are creating a standalone HTML document, as distinct from a fragment that is to be embedded in another document. The full command is:
pandoc -s -S --toc -c pandoc.css -A footer.html README -o example3.html
If you inspect the generated HTML file after running this, you will see it contains a line like this:
<link rel="stylesheet" href="pandoc.css" type="text/css">
That links to the CSS stylesheet, keeping the formatting information separate from the content. Very good practice if you’re publishing a document on the web.
But what about that “standalone” idea that you expressed with the -s option? What that does is make sure that the HTML is a complete document, beginning with a DOCTYPE tag, an tag, and so on. But if, for example, you have to email the document you just created, or upload it to your company’s document store, then things fall apart. When your reader opens it, they’ll see what you wrote, all right; but it won’t be styled the way you wanted it. Because that pandoc.css file with the styling is back on your machine, in the same directory as the original Markdown file.
What you really want is to use embedded CSS; you want the content of pandoc.css to be included along with the prose you wrote in your HTML file.
Luckily HTML supports that, and Pandoc provides a way to make it all happen: the -H option, or using its long form, –include-in-header=FILE
First you’ll have to make sure that your pandoc.css file1 starts and ends with HTML tags, so it should look something like this:
<style type="text/css">
body {
margin: auto;
padding-right: 1em;
padding-left: 1em;
max-width: 44em;
border-left: 1px solid black;
border-right: 1px solid black;
color: black;
font-family: Verdana, sans-serif;
font-size: 100%;
line-height: 140%;
color: #333;
}
</style>
Then run the pandoc command like this:
pandoc -s -S --toc -H pandoc.css -A footer.html README -o example3.html
and you’re done. A fully standalone HTML document.
- It doesn’t have to be called that, by the way.↩
Bash - how to recursively find the latest modified file in a directory
From the mighty Stack Overflow, some useful tips on using find with dates.
Weekend Warblers
The Radio 1 Hackney Weekend festival was fabulously well organised, loads of fun, and passed off with only three arrests.1 Booking the tickets a month or two ago had turned out to be easy (we sat with multiple browsers and phones as the SeeTickets site crumpled, but in fact it was no trouble at all after we left it for a while). Being local residents helped, as half the tickets were for Hackney households.
It was a free show, so there were restrictions; most notably that you could only book for one of the two days, and only two tickets per person. We were doing it for the kids; and the kids in this family (to say nothing of most of their friends) favoured the Sunday lineup; so that’s the one we went for.
The lineup leaned heavily to the various dance subgenres: (modern) R&B, dubstep, and so on. Not forgetting hip-hop, of course; not only did Jay-Z headline the first night, he guested with Rihanna on the second.
For me the highlight of the day was Jessie J; though I was mildly disappointed that she censored herself in my favourite of her songs, ‘Do it Like a Dude’.2
Tinie Tempah was also good, though since I’ve subsequently been listening to Enter Shikari, I’m slightly disappointed to have missed them as they clashed with Tinie.
There was great secrecy and much speculation over who the “Special Guest” was to be. They managed to keep it hidden until the day, which, while impressive in its way, had me worried. I thought that, depending on who it was, there could be a disaster. In particular, if it had been Justin Bieber, as some kids were speculating, there would have been a vast, simultaneous, two-way flow, from and to the stage (my kids would have been running away from the stage; there are no Beliebers at Devilgate Towers).
Not long before the guest’s time I heard on good authority that it was going to be Beyoncé. Believable, as her hubbie was there, and she was said to be “in the house”. But I doubted it: isn’t she a bigger name than Rihanna? And anyway, I get the sense that she’d be too much of a diva to go on second on the bill.
Anyway, in the end it was Dizzee Rascal, which with hindsight made total sense, what with him being a local boy and all.
As we wandered through the stages and the day, we heard snatches of Rihanna’s ‘We Found Love’ seven times (I started keeping count at the third) from various between-act DJs and stalls. So by the time it closed the night, I was thoroughly ready to hear it properly. And a damn fine ending it was, too (though the fireworks were a tad tame).
I was hugely impressed with the organisation of the thing. We got there nice and early, and there was hardly any queueing, despite the airport-style security. The staff were all lovely and friendly, and – get this – there was hardly ever a queue for the toilets!
I would strongly support any moves to make it a regular thing. Radio 1’s event moves around the country, so it couldn’t stay free, but I could easily see it working as a commercial festival in the future.
A Line, a Loop, a Tangle of Timey-Wimeyness
This week, though, I’ve been to the presentation of the Clarke Award, which is held in association with the festival, and at its main venue; and last night, the whole family went to the BFI (or the NFT, I can’t quite work out what its official name is these days) to see a film.
Which was Dimensions, a low-budget British film about time travel – or maybe dimension-hopping – which doesn’t even have a distributor yet.
Which is a great shame, because despite some flaws it is a very enjoyable piece. We were still talking about it at lunchtime today.
It’s also something of a costume drama, being set in the 1920s and 30s. The Sci-Fi-London page about it likens it to Merchant-Ivory.
It did show its low-budget nature in one or two places, but nothing that destroys the overall effect. The couple who made it (Ant Neely wrote and composed the original music, and Sloane U’Ren directed and did much else) had to sell their house to fund it, so almost anything can be forgiven.
I won’t say too much more about it here, but if you ever get a chance to see it, you should take it.
There was a Q&A with writer, director, lead actor & editor after the screening, which was very interesting. I was geared up to ask a question, which would have gone something like this: “When you make a time-travel story, especially in Britain, you’re walking among some long shadows, especially Wells and Doctor Who; to what extent would you acknowledge those as influences?” I had my hand up to speak, when the interviewer asked a question touching on exactly those points. So I didn’t ask. Pity. I would also have mentioned the fact that they have a mysterious wise man know only as “the Professor”.
Anyway, lots of fun: highly recommended.
Voting Time Again
Time to hit the polling booths again. Doesn't seem that long since the last one. But it's a lot easier to decide this time. Brian Paddick's a decent guy, but the Lib Dems have shown they can't be trusted over the last two years.
Boris hasn’t been quite the disaster we feared four years ago, but he still cares more about the richer members of society than everyone else. Plus, he’s a Tory. But I repeat myself.
Ken seems kind of past his peak, but he’s still the one for the job. Though I might give Jenny Jones my first vote and Ken my second. I think that’s what I did last time, come to think o it.
For the Assembly it’s going to be Labour all the way. I’m not impressed with how they’re doing in opposition at Westminster: the Tories are down, but they don’t seem to be kicking. Kick harder, Milliband! But to run London? Obviously it’s got to be the (relatively) good guys.
What’s surprising and slightly scary is the number of extreme-right parties who have put candidates up. obviously there’s the BNP and UKIP: but who knew the National Front were still around? Then there’s ones with names like England First and Christians Against Marriage Equality. (Those names may not be exact, but I’m on the Tube at the time of writing, so I can’t check; but you get the gist.)
Anyway, that’s where we are today. Don’t forget to vote if you can, folks.
Weird Law-Enforcement Things
There were three slightly weird law-enforcement- or intelligence-related stories in the news today:
- Two jailed in Northern Ireland over police officer's murder.
I heard the policeman’s wife on the radio. She spoke calmly about how getting the murderers off the streets was good for the community, and positively about the people who had bravely given evidence (at least one had to be given protection).
The odd, disturbing, and intelligence-community-related thing is that army intelligence had a tracker device in the car of one of the murderers, and at first they refused to reveal its details to the police undertaking the investigation. The police had to threaten to get a warrant. Then when they did provide the data, it turned out to have sections mysteriously missing. You have to sympathise with the PSNI here: they had both the Continuity IRA bampots and the army working against them.
'Dark Arts' involved in MI6 officer's death.
So what, this GCHQ codebreaker on secondment locked himself inside a bag using magic? I’m surprised that they’re even considering that it might not be murder here; or at least that someone has covered something up. More importantly, there’s the fact that the DNA evidence got messed up by a typo. Surely there’s got to be a better way?
Police officers deleted records of crime gangs
And then there’s this business about the corruption in the Met. Evidence allegedly deleted on the orders of crime gangs? That’s some scary stuff. I’m pretty sure that when the Serious Organised Crime Agency was set up, it was meant to be anti-organised crime.
No real connection between these, I just heard about them all today.
A Drop of the Hard Stuff
...potential readers are still coming to the genre. Books aren't the entry drug any more. Books are the hard stuff, the crystal meth of genre.
Paul Weller in "Good Album" Shock!
Who would have thought, this many years after The Jam, that Paul Weller could still make a decent album? Yet that's exactly what he's done. You can listen to it at The Quietus, an online music magazine.
Penguin Pete's Blog - Using Bash To Solve A Brain Teaser
[Great use of Bash scripting to do a maths puzzle, but demonstrating lots of useful features.](http://penguinpetes.com/b2evo/index.php?title=using_bash_to_solve_a_brain_teaser&more=1&c=1&tb=1&pb=1)
Terror, or Not; and Bail
I’ve been meaning to write a post about the Abu Qatada situation. But Jack Deighton has said all I would have; most notably, “If we do not behave in a better way than those who are against what we stand for then we would be worse than them.”.
The BBC lists Qatada’s bail conditions. Why the emphasis on technology, you have to wonder? Is he going to terrorise us over the internet?
Pass-By-Reference Problem When Using Websphere Application Server
This has been kicking around, nearly finished, for months. It's not going to get any better, or shorter, so it's long past time I put it out there.
It’s also just long; and technical. So feel free to ignore. I won’t be offended.
I rarely write about programming or other technical issues here, but I probably should do so more often. Certainly in a case like this.
I often think about the many, many problems that I’ve had help with from strangers on the internet; people who have taken the time to write blog posts, answers to questions on forums, or technology tutorials. My job would barely be possible at times without the web. Of course, we didn’t have it back when I started in 1987; but we didn’t do such complex things, with so many different languages and technologies.
Anyway, all these kind strangers have helped me, and I rarely find myself in a position to give anything back to the community. So since I recently hit a problem that no-one else seems to have had, it’s really my duty to describe it, and my solution, in the hope that it might be of use to someone down the line.
If you’re looking for the solution to the problem with pass-by reference on WAS, and don’t want to read the story of how I got there, you can jump straight to The New Bug
Background
We develop our main app using a fairly standard n-tier architecture using JEE: web front end using JSPs and Struts; EJBs; a multiplicity of database platforms accessed using Spring. All fairly standard stuff, whose purpose is to move financial messages around.
A lot of this was originally developed when I wasn’t around (I was seconded to another department) and by contractors and others who are no longer with us. So I take no responsibility for the stupidities that exist in codebase. Or rather, I accept no blame. I do, in fact, have responsibility for it; for keeping it going and developing it onwards now.1
One of the bad choices that was made by the original developers of this version of the product, was that they should cache the results of database queries. The users can define various criteria by which they want to select a set of messages to view; those get translated into SQL, which our Java code executes using JDBC. Again, all standard stuff. JDBC was designed for exactly that kind of thing. Databases exist solely to do that kind of thing.
So the wise and sensible developers decided that performance would be a problem if a query returned many rows from the database. They decided that transferring the rows to the browser and allowing the user to scroll through them would be impossible. So they designed a caching mechanism.
Thing is, JDBC has that kind of caching built right in. And furthermore, they (our developers) included a limit: a maximum number of rows to return, which could be set to 50, 100, 500, or 1000. Pretty reasonable, since any query that returned over 200 or so rows is likely to be less than useful, anyway.
But they still built that caching mechanism.
The Mechanism
That’s all right, though, I hear you say. Cache the rows server-side in memory, return a subset to the user as they page through them. It sounds fine.
True enough. Except they didn’t cache them in memory. Oh no. That would have been too sensible. And might have caused performance problems (I’m sure they thought, if they even considered they matter). No, they cached them elsewhere. Where? In the database.
Yes, they introduced another table; a shadow table; an almost-identical duplicate of the Messages table, called MessageQueryResults. Executing a query then consisted of selecting the required rows and writing them into this table, keyed by the HTTP session ID; and then re-querying this results table to get a page worth of results.
So, to recap, then: to improve performance (without first determining that there was actually a problem), they replaced a simple database read with a read, a set of writes, and another set of reads.
That was bound to perform better, right?
The Failure
It wasn’t performance that brought this flimsy edifice crashing down, though.2 No, it actually ran quite successfully for several years. Three things brought about its end: Microsoft, multiplicity, and me.3
Microsoft’s part was through their database platform, SQL Server. Between one version and another they changed something about their storage mechanism, so that you could no longer rely on rows on a table being in the sequence in which they were written to the table. The thing is, you’re not supposed to be able to rely on that, according to DB theory. That was another flaw in the “design” above; it relied on the shadow table’s rows being returned in the same sequence they were written in. On Oracle and DB2 that worked; and it did on SQL Server too, until (if memory serves) the 2005 version. This meant that clients on that platform who had large queries couldn’t rely on them being displayed in the right order.
Oh dear.
Hacks were applied to sort this out. Pun intended: sorting is pretty much what they did. Not a fix, but a workaround at best.
The multiplicity part was that the same mechanism was used to query another table; and then a third. And there was a fourth on the horizon. Each new table meant a new shadow table which had to be maintained in parallel – and whose creation and upgrade scripts had to be maintained across three database platforms. A maintenance nightmare.
Then there was me. I had known about the problem for some time, of course – I had done an estimate for fixing it – but there was never time to fix it. It was a big task, quite intrusive, and showing no easily-provable customer benefit. Yes, I know ease of maintenance, by making life easier for developers, is an implicit customer benefit; but try selling that to management, when there are customers crying out for new features.
But in the project that was to introduce the fourth table (or seventh and eighth, you might say) I was in a position to say, “we fix this first, or it all goes to hell”.
The user story was written. I got my estimate out of hibernation (and increased it, of course). And then I did the fix. It was a great joy. That in-memory caching mechanism I mentioned above? I did that. If I’d been designing it from scratch I would almost certainly have relied on JDBC’s internal caching, at least until it proved problematic. But under the circumstances, when the code relied on there being a cache, it was going to be much less disruptive to retain one. I just replaced the stupid one with a more sensible one.
Inevitably, though, I introduced a new bug.
The New Bug
This is where I stop telling a story and start explaining the problem and solution.
Introducing the new message caching mechanism, which replaced the MessageQueryResults table, inadvertently caused a problem when we set a WAS server to pass-by-reference mode.
This mode is recommended when the different tiers of the application (web, EJB) are running in the same JVM. This is normally the case in our test environments, and frequently the case in client systems. Enabling this mode removes the need for objects to be copied as they are passed through the tiers, and can improve performance dramatically in such environments.
What Went Wrong
Changing the caching mechanism caused no problem as long as pass-by-reference was off. As soon as it was turned on, we noticed that taking certain actions, such as deleting a message, failed.
The failure was at a point in the code where the a value such as an amount was being retrieved from the Map that formed the new cache. The failure was that the retrieved Object was being cast to a Number, but what was in the Map entry was actually a String.
This Map comes, by a fairly complex set of steps, from the new cache, and before that from the database itself, of course.
Now, since the Amount column on the DB is numeric, and the Map in question is originally populated via Spring from the DB, obviously the value was a numeric one originally. This suggested that the value must have been changed, and that gave us the first clue to tracking down the cause of the problem, and coming up with a solution.
The Cause
It seemed likely – and running debug, it was shown to be so – that the numeric value that was retrieved from the database and stored in the Map was being replaced by the edited value which is built for displaying. In other words, the object now contained a String holding digits, a decimal point, and probably commas.
Why it Changed When We Switched on Pass-By-Reference
When the data was being passed by value, a new Map, complete with its contents, was being passed from the EJB layer to the webapp. The webapp then updated values in that Map, editing them for display purposes. But it was only changing its own copy; it had no effect on the version stored back in the EJB layer. So when the same Map was retrieved again, so that the action could be performed, a new copy was received by the webapp. No problem.
But when pass-by-reference is on, no copy is made. The webapp receives a reference to the actual Map that is stored in the cache back in the EJB layer. So when it updates an entry in that Map, it updates the very object that is stored in the cache (note that the put method of the Map interface will update the stored value if it receives a key that it already holds).
And then when the Map and its entry are retrieved again for the action to be performed, it is the updated (and now wrong) version that is retrieved.
Why it Changed When We Changed the Caching Mechanism
And yet both possible passing settings were available before we changed the caching mechanism. Why did we not get this problem when using pass-by-reference with the old caching mechanism?
The answer to that is that the old mechanism cached the query results in the database itself, in the MessageQueryResults table. Each time a set of results was requested by the webapp, the EJB layer went back to this temporary table and populated the Map that it returned to the webapp. So the amount value would always have been set up freshly from the numeric Amount column, which ensured that it was an object of type Number.
The Fix
I tried making copies of the Maps and Lists used, at various points in the process, including using ImmutableLists and ImmutableMaps from Google’s Guava library, in an attempt to prevent the value object of interest from being updated. However, it wasn’t possible to make them immutable deeply enough (and would probably have caused other problems if it had been). That was largely because the principal Map is created and populated by Spring, so we don’t have much control over it.
One solution – and probably the proper one – would have been to copy the entries from the Map at the point they are read and processed in the webapp. This would have meant that the edited, String, version of amount would be a different, new object, and would not have been updated in the Map that came from the cache.
However, the vast complexity of the class where this would have had to happen made this seem like a very difficult and dangerous approach, especially at this late point in the project.
An alternative solution was suggested by one of my colleagues. It was to accept the fact that the amount value might be a String containing a numeric value with commas and decimal point, and to parse the numeric value out of it.
This allowed us to cater for both numeric and string values, and it worked with either form of passing semantics. But it felt like a hack, and I was sure it would come back to bite us.
Fixing the Fix, a Little Later
It did. The trigger this time was paging through the list of results; when you returned to a page you had already seen, you ended up with an object of the wrong kind coming out of the Map. If memory serves it was a String where it should have been a Date.
It was clearly another result of the data being edited for display and updated in-place in the Map. There are too many possible places in in the relevant method to rely on finding them all, so I returned to the “probably the proper” solution mentioned above. I changed the relevant method such that it now returns a copy of the List containing the required subset of the query results. This is less straightforward than might be hoped, because copying a List, including by the clone method of the implementing class, for example, tends to do a “shallow copy”, which means that you get a new List instance, but containing references to the same objects.
I wrote a method called copyList, which iterates over a List and makes “deep” copies of a few expected types of object. We may have to extend this method to handle other types, but I don’t expect that at the moment.
Also Worth Noting
There is a warning about this on IBM’s Best Practice: Using pass by reference for EJBs and servlets if in same JVM page, but it’s one of those typical contrived kind of examples that probably wouldn’t really alert you to the possibility of something like my experience.
Notes
To set the pass-by-reference mode on or off, take the following steps in the WAS administrative console (this is WAS 6, it’s probably different at other releases).
Go to Servers -> Application servers -> <server -name>
Expand Container Services; click on ORB Service; check/uncheck “Pass by reference”
Your Friendly Olympic Park
This is the view from the banks of the Lea (or Lee) by the Olympic Park:
Let’s take a closer look at that attractive fence:
Lovely, eh?
I hope they take it all away and make it nice and open, but I suspect they won’t, at least until after the Games.
Cluttered by Google, Lost by Bing
I was reading The Clutter Didn’t Kill the Love by Brent Simmons, about how he was trying Microsoft's Bing search engine, instead of Google. His reason was the current worry that Google is becoming less than trustworthy.
Google losing trust would be a shame. But at least a Google search for “martin mccallion” (without the quotes) has this blog as the number one hit. Try that on Bing at the moment and you get a whole pile of other Martin McCallions.1 The worst part to me is that the first six are Facebook or LinkedIn profiles (the seventh is one of those annoying directory sites, then you get me).
I wouldn’t mind other people with the same name appearing above me, if it was their proper sites; but to me social-network profiles feel like distinctly second-class web entities.
Or is that snobbish?
-
As an experiment, and to ensure a like-for-like comparison, I signed out of Google, and went to the .com version (I normally use .co.uk by default). I was still at the top. ↩︎
The Felice Brothers
As if there weren’t enough reasons to love Outnumbered already, we recently saw an old Christmas special. It ended with the family watching the telly and singing along to a song. I didn’t know it, but liked the sound of it.
The internet knows all, and a bit of googling told me it was ‘Frankie’s Gun!’ by The Felice Brothers.
Emusic has the relevant album, and it’s great. Highly recommended.
Also their site tells me they’re playing London on the 20th of March. Hmmm…
Autumn Roses
[gallery link="file" columns="9"]
This warm autumn has done some weird things in our garden. The end of November in Hackney brought these new blooms out. They’re still there now, though they won’t be for long, now that it’s proper winter.
Those pictures above are supposed to come out side-by-side, not one above the other, but that doesn’t seem to be working. Oh well.
The Words that Maketh Novels
It seems like almost no time at all since I last wrote about not completing NaNoWriMo. But here we are again. A year passes like nothing.
I wasn’t strictly following the rules (but they’re only really guidelines, and optional at that) in that I wasn’t starting a new novel this time. I was carrying on the same one that I started last year, and I hadn’t written many more in the interim. I managed just under 15,000 words this year, which is slightly less than last time (and less than a tenth of my erstwhile OU Creative Writing classmate Karl’s crazy figure)
It has, however, given me a new kickstart, and I intend to carry the momentum onwards, but at a more manageable rate. My novel (working title Accidental Upgrade) currently stands at around 36,000 words. I’ve set myself a target of 80,000 by the end of February. That is more like the length of a modern novel, and achievable at a rate of around 475 words a day, according to Scrivener.
That’s much more feasible for me than Nano’s 1667. Though I’m just realising that I said essentially the same thing last year, and it obviously didn’t work. Still, I feel more confident this time. I wrote around 600 words today, and I’ve got Scrivener to help me keep on track.
Smashing Things Up for 35 Years
My friend (Wee) John(ny) called a couple of days ago and said, “Do you fancy seeing The Damned at the Roundhouse?” I’d never been to the Roundhouse, though it was one of those legendary London venues from my teenage years, like the Rainbow and the Hammersmith Palais. And I hadn’t seen The Damned in (I thought)1 about 26 years. Not since a seated gig in the Edinburgh Playhouse the night before I had a High-Energy Physics progress test the following morning.2
I said “Yes”. I mean, why the hell not? I only really know Machine-Gun Etiquette and a few singles, but what the hell. They’re bound to do those, right? It’s a 35th-anniversary thing.
The Roundhouse is an amazing place. As a former railway shed, it’s just a stunning space. But it’s not the seedy old-school venue I half expected, because it’s been closed down and refurbished and reopened since the seventies. So it’s really nice: more like The Barbican, say, than The Forum.
Viv Albertine was supporting. I expected her to have a band, but she just stood up there on her own, with a Telecaster as old as punk, and sang us songs of non-love and stuff. She was great.
The Damned were… pretty much as I expected, actually. They came on, and the Captain said, “We’re going to do two ‘classic’ albums.” (He did the air-quotes.) I’m not sure about this recentish trend of doing a whole album live, but expect it could be good. Mostly, though, I’m amused that for classic punk albums, one would be too short.
So they kicked off into ‘Neat Neat Neat’, and I realised that we were much too close to the front: actually in the moshpit. As I’ve said, I’m really past that — much though I might enjoy dancing in the abstract, or in private.
Anyway, it was all very wild and excellent, and there were many people with t-shirts of bands I’ve seen or haven’t seen but wish I had or don’t mind that I haven’t but recognise anyway. In short, I was with, as Neil Gaiman describes it, my tribe.
It was all monstrously fine. Two albums with a break, then a few encores. Which included, as expected, several non-those-album tracks. ‘Love Song’, of course, they could hardly have avoided playing. A couple of others, and then came ‘Eloise’, which, punked-up though it was, we could frankly have done without,
Then they played ‘Anti-pope’ and were gone. I realise that the Roundhouse must have a strict 11 o’clock policy, but surely they were coming back…? No. DJ music and house lights… and no ‘Smash it Up’. I must admit, if you had asked me before I went out tonight whether there was any chance that they wouldn’t play ‘Smash it Up’, I would have laughed at you.
Very strange. And then there was a crazy queue to get out of the venue, because so many people had taken up the option to get an instant double CD of tonight’s gig. They obviously burn them straight from the sound desk while the gig is on. But it meant that you could hardly get out of the venue. There has to be a better way than that.
Anyway, my ears are sizzling, and I still owe NaNoWriMo a load of words, so I’ll call it a night here.
