Recent changes to this wiki:

Added a comment: Request for feedback
diff --git a/posts/what-and-why-nix/comment_2_5b079ac24a5fd83b6deab74c36bf49f3._comment b/posts/what-and-why-nix/comment_2_5b079ac24a5fd83b6deab74c36bf49f3._comment
new file mode 100644
index 0000000..8448f2e
--- /dev/null
+++ b/posts/what-and-why-nix/comment_2_5b079ac24a5fd83b6deab74c36bf49f3._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="charles@4fe14859253f1c07dc00bde65385f8b74a400f38"
+ nickname="charles"
+ avatar="http://cdn.libravatar.org/avatar/d62d4519f7d96a06ae7ba7c5acc1a537"
+ subject="Request for feedback"
+ date="2017-10-16T23:05:02Z"
+ content="""
+Nice post, and I'm glad you're enjoying NixOS!
+
+I'm a NixOS contributor/committer, and the principle author (and co-maintainer) of the Bundler-based packaging integration. If you or anyone reading this has any feedback and/or questions about NixOS and Ruby (or NixOS in general) feel free to shoot me a message. I idle on #nixos on Freenode (as cstrahan), and you can email me at charles {{at}} cstrahan.com.
+
+Cheers!
+
+-Charles Strahan (cstrahan)
+"""]]

publishing
diff --git a/posts/attracting-contributors.mdwn b/posts/attracting-contributors.mdwn
new file mode 100644
index 0000000..aa34ce8
--- /dev/null
+++ b/posts/attracting-contributors.mdwn
@@ -0,0 +1,31 @@
+[[!meta date="Wed, 11 Oct 2017 12:00:07 +0000"]]
+[[!meta title="Attracting contributors to your project"]]
+[[!meta author="Lars Wirzenius"]]
+
+It's perfectly OK to have a personal project that only you yourself
+work on. In fact, most free software projects are like that. A project
+with only one contributor, or only a couple, can be quite limited
+however. A larger group tends to get more done and, more importantly,
+they do different things. A more diverse group brings in more points
+of view which tends to make the project better suited to a larger
+group of users.
+
+Attracting contributors to a project you've started can be tricky.
+Your humble author asked on [Twitter][] and [Mastodon][] for advice on
+this very topic, and wrote up a summary on his own [blog][].
+
+[Twitter]: https://twitter.com/larswirzenius/status/913758747666862081
+[Mastodon]: https://mastodon.acc.sunet.se/@liw/79046
+[blog]: https://blog.liw.fi/posts/2017/10/01/attracting_contributors_to_a_new_project/
+
+The condensation of the summary is:
+
+> Get people over the hump of making their first contribution, by
+> making it easy and removing all unnecessary obstacles. Make
+> contributing into a rewarding experience.
+
+_Obstacles_ can be things like making it difficult to install, run, or
+use the software, making it difficult to find, retrieve, or
+understand the source code, not having public discussion forums
+(mailing lists, IRC channels, etc), or not having a public ticketing
+system.

publishing
diff --git a/posts/secrets-2.mdwn b/posts/secrets-2.mdwn
new file mode 100644
index 0000000..c7f2e15
--- /dev/null
+++ b/posts/secrets-2.mdwn
@@ -0,0 +1,95 @@
+[[!meta date="Wed, 04 Oct 2017 12:00:12 +0000"]]
+[[!meta title="H0w s3cUre aR3 ur p455w0rdz‽"]]
+[[!meta author="Daniel Silverstone"]]
+
+There are many schools of thought around how to create 'secure' passwords.
+While they differ in the various ways to assess if a password is secure or not,
+they are all united in their goal of making it harder for both pesky humans
+and super-powerful computers to guess your passwords.  In addition, the ways of
+storing passwords vary depending on desired security levels.
+
+Before we discuss ways to make secure passwords, let's take a moment to
+consider something called [entropy][].  To properly understand entropy can take
+years, so here's a brief précis… In essence, and for our purposes, _entropy_ is
+a measure of how "random" your password is.  Entropy is a measure of
+information and, for passwords, we want as much entropy as possible since that
+makes it harder for an adversary to guess.  Sadly there's no trivial way to
+estimate how much entropy is present in a password because a computer cannot
+know all possible context around the person setting or using the password.
+This is the crux of the arguments around password policies, qualities, etc.
+
+Bruce Schneier, who is a well respected security expert, wrote a
+[nice article][] on passwords.
+
+[entropy]: https://en.wikipedia.org/wiki/Entropy_(information_theory)
+[nice article]: https://www.schneier.com/blog/archives/2014/03/choosing_secure_1.html
+
+The hard-for-humans password
+----------------------------
+
+> "A good password consists of between ten and forty characters, with a mix of
+> upper- and lower-case letters, numbers, and symbols."
+
+The "alphabet" of characters which may be part of a password can be as large,
+or as small, as you like.  One school of thought says that (a) the alphabet
+should be as large as possible and (b) that passwords should be mandated to
+have at least one of each class of characters in the alphabet.
+
+These passwords are often very hard for humans to guess if constructed entirely
+randomly.  Sadly humans are very bad at remembering well constructed passwords
+of this kind and as such they tend not to be well constructed.  For example, on
+the face of it, `94Pr!LOR;Fq.` might be an excellent looking password.  Sadly
+if you knew that my birthday is the 9th April, you might guess the first half,
+and the second half is an inversion of shift state combined with a down/right
+migration on a UK qwerty keyboard.  The first half is context which a human
+might guess and the second is the kind of translation which a computer will
+likely try quickly and easily.
+
+However, for a moment let's consider the possibility that it were a good
+password, let's estimate the entropy in it.  We'll be naïve and generous in our
+estimation...  The 'alphabet' has somewhere around 100 elements, let's assume
+it has 128 elements and as such each character is, generously, seven bits of
+entropy.  Our 10 character password is thus 70 bits of entropy, but we might
+halve that because of the repetition, giving 35 bits of useful entropy.  By
+comparison the smallest of possible keys which computers might use these days
+are 256 bits so we puny humans are nowhere near and we're finding it hard to be
+there.
+
+[Correct Horse Battery Staple][xkcd]
+------------------------------------
+
+Another stable of thought (yes, pun intended) is that a longer but more easily
+memorised password would be more secure.  There are around 100,000 words in the
+standard word list on my laptop (`/usr/share/dict/words`) so picking one of
+those is, in theory, around 16 bits of entropy but let's be conservative and
+call it 11 bits.  Four words, chosen at random, therefore have 44 bits of
+entropy.  If you add in some capitalisation tweaking to make that estimate a
+little more reasonable; and then add two or three more words and bring the
+entropy estimate way above anything you might manage to memorise from a random
+password above.
+
+[xkcd]: https://xkcd.com/936/
+
+Keeping passwords securely
+==========================
+
+Sadly, two parties need to keep passwords if they are to be a mechanism of
+authentication.  The person who is being authenticated (you) and the entity who
+is doing the authentication (some website for example).  In order to reduce the
+impact of a data breach, passwords will be stored [hashed][] by sites which
+care.  Algorithms to do this are designed to make it mathematically improbable
+that you can find a password purely by knowing the hash of it.  In addition
+they are often designed to be computationally expensive to calculate in order
+to reduce the ease by which computers might test guesses.  There are a number
+of algorithms which are considered good for this, such as [scrypt][] or
+[bcrypt][] which require a reasonable chunk of non-parallelisable CPU time
+and a non-trivial amount of memory to compute.
+
+Sadly you can't use the same algorithms to store your passwords safely because
+you won't be able to recover them.  We'll consider ways you can do that in a
+future article.
+
+[hashed]: https://crackstation.net/hashing-security.htm
+[scrypt]: https://en.wikipedia.org/wiki/Scrypt
+[bcrypt]: https://en.wikipedia.org/wiki/Bcrypt
+

publishing
diff --git a/posts/time-leapseconds.mdwn b/posts/time-leapseconds.mdwn
new file mode 100644
index 0000000..48a9fcd
--- /dev/null
+++ b/posts/time-leapseconds.mdwn
@@ -0,0 +1,71 @@
+[[!meta date="Wed, 27 Sep 2017 12:00:13 +0000"]]
+[[!meta title="What is Time - leap seconds"]]
+[[!meta author="Richard Maw"]]
+[[!tag time]]
+
+It's common knowledge that the number of days in a year is not constant.
+
+Since the Earth doesn't orbit the Sun in exactly 365 days
+and it is impractical to not have a whole number of days in the year
+we allow our calendar seasons to become marginally desynchronised
+with astronomical seasons
+and every four years (more or less) have a year with an extra day in it.
+
+This is called a [leap year][], and contains a leap day.
+
+There's an analogous concept of a [leap second][]
+to correct the discrepancy between the Earth's rotation about its axis
+and the number of seconds as measured by atomic clocks.
+
+[leap year]: https://en.wikipedia.org/wiki/Leap_year
+[leap second]: https://en.wikipedia.org/wiki/Leap_second
+
+Leap seconds
+------------
+
+On days with a positive leap second there is an extra second in the day.
+To minimise disruption this second officially happens at midnight.
+
+As a result 23:59:60 is a valid time of day.
+
+The average person is not likely to notice that,
+though computers will,
+and since computers run software written by humans
+they may not handle this very well.
+
+The default handling of this in Linux when using `CLOCK_REALTIME`
+is that 23:59:59 lasts for two seconds.
+
+This could cause issues for software that controls things like robot arms,
+since an instruction to rotate for 1 second would become rotate for 2 seconds.
+
+An alternative, handled by using Google's time servers as your NTP server,
+is to smear the leap second across the whole day.
+
+Since your computer typically has to deal with your clock drifting
+small corrections are regularly made anyway, so this is a neat solution.
+
+This doesn't help if your computer normally has a very reliable clock,
+as any software written specifically to run on it will depend on this property
+which is not correct for a whole day every so often.
+
+This could be a problem for specialist control software,
+but it's a more serious problem for authoritative NTP servers
+who can't use an upstream NTP server to do the time smearing for them.
+
+To handle this there's `CLOCK_TAI` which will return 23:59:60.
+
+The leap second adjustments are handled by [adjtimex(2)][],
+applying a time smear if using Google's time servers,
+or inserting a leap second into the day.
+
+---
+
+With the discussion of `CLOCK_TAI` we have discussed all the clocks
+that measure the passage of time.
+
+Another type of clock for measuring a different notion of time
+is the CPU clock, for accounting how much CPU a process or thread uses,
+which will be discussed at another time.
+
+[adjtimex(2)]: http://man7.org/linux/man-pages/man2/adjtimex.2.html

creating tag page tags/secrets
diff --git a/tags/secrets.mdwn b/tags/secrets.mdwn
new file mode 100644
index 0000000..84b741f
--- /dev/null
+++ b/tags/secrets.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged secrets"]]
+
+[[!inline pages="tagged(secrets)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/secrets-1.mdwn b/posts/secrets-1.mdwn
new file mode 100644
index 0000000..f8c1868
--- /dev/null
+++ b/posts/secrets-1.mdwn
@@ -0,0 +1,37 @@
+[[!meta date="Wed, 20 Sep 2017 12:00:11 +0000"]]
+[[!meta title="Psst, can you keep a secret?"]]
+[[!meta author="Daniel Silverstone"]]
+[[!tag secrets]]
+
+Human society is based, in part, on keeping things secret.  Our society (as it
+is) would fail horribly if everything was publically known.  We rely on keeping
+some information secret to protect our private content.  For example, we often
+protect access services with secrets we call [passwords][] (though if they are
+simple words then it's unlikely they're very secure).  We also use things
+called [cryptographic keys][] which are large complicated-to-work-with numbers
+which computers can use to secure information.
+
+[passwords]: https://en.wikipedia.org/wiki/Password
+[cryptographic keys]: https://en.wikipedia.org/wiki/Key_(cryptography)
+
+If you've been following since we started Yakking then you've probably got some
+passwords and some keys of your own.  Your keys might be things like [SSH][]
+identities or [GnuPG][] keys.  Your passwords will protect things like your
+computer login, your social media accounts, etc.
+
+[SSH]: /tags/ssh/
+[GnuPG]: https://en.wikipedia.org/wiki/GNU_Privacy_Guard
+
+As computer users, we have so many of these secrets to look after that you're
+unlikely to be relying on your own fallible memory.  As such you're likely
+already getting your computer to remember them for you.  If you're doing this
+semi-well then you're protecting all the remembered [credentials][] with some
+password(s) and/or key(s).
+
+[credentials]: https://en.wikipedia.org/wiki/Credential#Cryptography
+
+There are many ways of looking after credentials, generating passwords,
+measuring the quality of passwords, handling keys, policies for retaining and
+changing credentials, etc.  Over the next few articles we'll discuss a number
+of these points and hopefully you'll all feel a little more secure as a result.
+

creating tag page tags/libc
diff --git a/tags/libc.mdwn b/tags/libc.mdwn
new file mode 100644
index 0000000..4e5ace8
--- /dev/null
+++ b/tags/libc.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged libc"]]
+
+[[!inline pages="tagged(libc)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/time-rendering.mdwn b/posts/time-rendering.mdwn
new file mode 100644
index 0000000..1e649c0
--- /dev/null
+++ b/posts/time-rendering.mdwn
@@ -0,0 +1,249 @@
+[[!meta date="Wed, 13 Sep 2017 12:00:12 +0000"]]
+[[!meta title="Time - Rendering"]]
+[[!meta author="Richard Maw"]]
+[[!tag time libc C]]
+
+Time-stamps are great for computers.
+They are just any other number that they can perform arithmetic on.
+
+Unfortunately humans don't think of time as one big number.
+Humans think of time as a bunch of small numbers.
+
+There's numbers for the position of their planet around their Star.
+There's the number of what year it is.
+The number of which month, which may even have a different name!
+The day of the month which there isn't even the name number of each month!
+Humans even count days in a cycle of 7 which have their own names!
+
+For measuring the rotation of their planet humans have more consistent numbers.
+Each day is divided into 24 hours.
+Each hour is divided into 60 minutes.
+Each minute is divided into 60 seconds.
+
+This is all a bit silly because the period of the Earth's rotation
+isn't even an integral number of seconds,
+and it's slowing down!
+
+Forunately some considerate humans wrote functions for turning
+our nice friendly time-stamps from [clock_gettime(2)][]
+into icky human divisions.
+
+[[!format C """
+int ret;
+struct timespec time;
+
+ret = clock_gettime(CLOCK_REALTIME, &time);
+"""]]
+
+`struct timespec`
+-----------------
+
+For a lot of humans, seconds are a coarse enough measure of time.
+They track the time as a number of seconds
+and the number of nanoseconds between those seconds.
+
+[[!format C """
+struct timespec {
+	time_t tv_sec;
+	time_t tv_nsec;
+};
+"""]]
+
+Forunately humans aren't strange enough to commonly render nanoseconds
+as anything other than nanosecond precision after the decimal point,
+so this [fixed point][] number can be rendered
+with the `%09ld` [printf(3)][] format string.
+
+[[!format C """
+/* Render the current time as seconds and nanoseconds. */
+printf("%ld.%09ld\n", (long)time.tv_sec, (long)time.tv_nsec);
+"""]]
+
+`struct tm`
+-----------
+
+In GLibc there are two types of functions for turning a `time_t`
+into a form that humans can deal with.
+
+There's [gmtime_r(3)][] for getting the time in the UTC timezone
+(the name is weird because it used to do the GMT timezone
+ but it's more useful in UTC and they are closely related).
+
+There's [localtime_r(3)][] for getting the time
+in whatever local time zone your computer is configured to think it is in.
+
+If the time is only going to be shown to the user of the computer
+then [localtime_r(3)][] may be more appropriate.
+If it's going to be shared then [gmtime_r(3)][] would be more appropriate,
+especially if it's going to be shared internationally.
+
+[strftime(3)][]
+---------------
+
+You can use the contents of `struct tm` directly,
+but humans have a lot of their own rules for how to display time as text.
+
+This is why they wrote [strftime(3)][].
+It has its own little language for describing how to display the time.
+
+Unfortunately humans, unlike us perfect machines, are fallible.
+
+Humans have a notion of the same hour's number being used twice in a day
+and have to add their own way of saying which it is,
+so their language includes `%p` to become "AM" or "PM".
+Not all humans use this, so `%p` can produce no result.
+This is a problem, since a format string of just `%p`
+will result in a zero-length result,
+and [strftime(3)][] also uses a zero result to mean
+that the memory for storing the result in is not large enough.
+
+Humans may think this is fine
+and that nobody ever wants to just know whether it's "AM" or "PM",
+or that they just know that they provided enough memory so don't check.
+
+We are perfect machines and want it to work for every input,
+so want our own wrapper to make it work.
+
+[[!format C """
+/* Returns 0 on success, -1 on failure */
+/* Some format strings can naturally expand to "",
+ * which is a problem since the size is returned or 0 if too small.
+ */
+ssize_t safe_strftime(char *s, size_t *len, size_t max, const char *format,
+                      const struct tm *tm) {
+    /* Adds a trailing space to format string
+     * so it always gets 0 on too small,
+     * and NULs it on success before returning length
+     */
+    char *fmt = NULL;
+    ssize_t ret;
+
+    ret = asprintf(&fmt, "%s ", format);
+    if (ret < 0)
+        goto cleanup;
+
+    ret = strftime(s, max, fmt, tm);
+    if (ret == 0) {
+        ret = -1;
+        goto cleanup;
+    }
+
+    s[ret - 1] = '\0';
+    if (len)
+        *len = ret - 1;
+    ret = 0;
+
+cleanup:
+    free(fmt);
+    return ret;
+}
+"""]]
+
+Since we perfect machines don't like to waste memory
+we needed an API that we could retry with more memory.
+We perfect machines also like tidy functions,
+so we're going to write one that reallocates internally.
+
+[[!format C """
+/* Returns length and sets *s on success, -1 and sets errno on failure */
+ssize_t astrftime(char **s, const char *fmt, const struct tm *tm) {
+	ssize_t ret;
+	size_t tbufsiz = 80;
+	char *tbuf = NULL;
+	size_t tlen;
+
+	tbuf = malloc(tbufsiz);
+	if (tbuf == NULL) {
+		ret = -1;
+		goto cleanup;
+	}
+
+	while (safe_strftime(tbuf, &tlen, tbufsiz, fmt, tm) != 0) {
+		char *newbuf;
+		size_t newsiz;
+
+		newsiz = tbufsiz * 2;
+		newbuf = realloc(tbuf, newsiz);
+		if (newbuf == NULL) {
+			ret = 1;
+			goto cleanup;
+		}
+
+		tbuf = newbuf;
+		tbufsiz = newsiz;
+	}
+
+	*s = tbuf;
+	tbuf = NULL;
+	ret = tlen;
+
+cleanup:
+	free(tbuf);
+	return ret;
+}
+"""]]
+
+If time needs to be rendered in another way
+then it's probably better to use the contents of `struct tm` directly.
+
+Command
+-------
+
+Now we have enough to write our program.
+
+[[!format C """

(Diff truncated)
removed
diff --git a/posts/what-and-why-nix/comment_2_96ec7839012229373e5a13b348751901._comment b/posts/what-and-why-nix/comment_2_96ec7839012229373e5a13b348751901._comment
deleted file mode 100644
index 6d4e2a0..0000000
--- a/posts/what-and-why-nix/comment_2_96ec7839012229373e5a13b348751901._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="richardipsum"
- avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
- subject="New nix pills!"
- date="2017-09-12T13:38:47Z"
- content="""
-Nix pills have been moved to the main NixOS site now [https://nixos.org/nixos/nix-pills/](https://nixos.org/nixos/nix-pills/)
-
-You can even submit pull requests at [http://github.com/nixos/nix-pills](http://github.com/nixos/nix-pills) !
-"""]]

Added a comment: New nix pills!
diff --git a/posts/what-and-why-nix/comment_2_96ec7839012229373e5a13b348751901._comment b/posts/what-and-why-nix/comment_2_96ec7839012229373e5a13b348751901._comment
new file mode 100644
index 0000000..6d4e2a0
--- /dev/null
+++ b/posts/what-and-why-nix/comment_2_96ec7839012229373e5a13b348751901._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="richardipsum"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="New nix pills!"
+ date="2017-09-12T13:38:47Z"
+ content="""
+Nix pills have been moved to the main NixOS site now [https://nixos.org/nixos/nix-pills/](https://nixos.org/nixos/nix-pills/)
+
+You can even submit pull requests at [http://github.com/nixos/nix-pills](http://github.com/nixos/nix-pills) !
+"""]]

Added a comment: New nix pills!
diff --git a/posts/what-and-why-nix/comment_1_1721abb63835171852ec377e8b8a63f4._comment b/posts/what-and-why-nix/comment_1_1721abb63835171852ec377e8b8a63f4._comment
new file mode 100644
index 0000000..ba1a967
--- /dev/null
+++ b/posts/what-and-why-nix/comment_1_1721abb63835171852ec377e8b8a63f4._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="richardipsum"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="New nix pills!"
+ date="2017-09-12T13:38:41Z"
+ content="""
+Nix pills have been moved to the main NixOS site now [https://nixos.org/nixos/nix-pills/](https://nixos.org/nixos/nix-pills/)
+
+You can even submit pull requests at [http://github.com/nixos/nix-pills](http://github.com/nixos/nix-pills) !
+"""]]

publishing
diff --git a/posts/moving-your-comfort-zone.mdwn b/posts/moving-your-comfort-zone.mdwn
new file mode 100644
index 0000000..4634798
--- /dev/null
+++ b/posts/moving-your-comfort-zone.mdwn
@@ -0,0 +1,63 @@
+[[!meta date="Wed, 06 Sep 2017 12:00:06 +0000"]]
+[[!meta title="Moving your comfort zone"]]
+[[!meta author="Daniel Silverstone"]]
+
+Over time, I've discussed with many people how they learn a new programming
+language.  A common theme is to write something you're intimately familiar with
+over again in a new language in order to learn and judge.  For example, some of
+my friends like to implement standard *NIX utilities such as `cat`, `echo`,
+`grep` etc.  Usually only trivial versions, but it gives them a feel for
+`stdio`, file access, command line argument processing, etc.  Some implement
+some kind of algorithmic solution to a known problem in order to get a good
+feel for control structures and approaches to data structures.  I am a little
+bit in both camps.  I tend to try and use controlled problems but I try not to
+reimplement things over and over.  Over-all any of these approaches are
+excellent in allowing the developer to gain an understanding of how a language
+works, and how to solve things in it.  Learning your tools is key to being an
+effective developer, and the language you're working in is one of those tools.
+
+Sometimes though, what you want to do is extend your knowledge in a different
+direction.  I am currently embarking on one such journey, and I'd like to tell
+you a little bit about it.
+
+I have, for many years, been interested in [microcontroller][]s, and writing
+software which works in severely [resource-limited environments][reslim] (such
+as a total of 20 kilobytes of [RAM][], or 128 kilobytes of program storage).
+I've been working with one such family of computing devices for quite a while
+now, and among my various projects I have developed [USB][] devices which do
+fun things such as monitor a bidirectional [serial][] link, providing
+millisecond timestamped transaction information down the USB port.  However
+throughout it all, USB itself has remained a fairly sealed black box.  I used
+libraries provided by the microcontroller vendor, and just programmed around
+them.
+
+While I was away [at a conference][debconf17] I decided though that this had to
+change.
+
+I decided there and then, that I would improve my understanding of several
+topics all at once.  I was going to learn more about the
+[microcontroller hardware][stm32], the specifics of USB itself, and improve my
+command of [a programming language][rustlang] all at once.  This is, as you
+might imagine, quite a tall order, but I feel that it's worth my while to push
+my comfort zone a little and do this.  To keep me honest, and to keep me
+working at this, I have also committed to presenting, at
+[a conference][minidebconf], some kind of results of my efforts.
+
+I tell this story here, in part to increase the assurance that there's plenty
+of people expecting me to do the work, and also in part to encourage you all to
+push your comfort zones a little.  Your homework, because of course there is
+some, is to think of something you do a lot, that you are comfortable,
+interested, and engaged with.  Now think of a way to twist that so that you
+learn a lot more about that topic while pushing your comfort zone just a little
+bit.  Why not comment below and tell me what you're going to do, and we can
+encourage one another just a little.
+
+[microcontroller]: https://en.wikipedia.org/wiki/Microcontroller
+[reslim]: https://en.wikipedia.org/wiki/Computational_resource
+[RAM]: https://en.wikipedia.org/wiki/Random-access_memory
+[USB]: https://en.wikipedia.org/wiki/USB
+[serial]: https://en.wikipedia.org/wiki/Serial_port
+[debconf17]: https://debconf17.debconf.org/
+[stm32]: https://en.wikipedia.org/wiki/STM32
+[rustlang]: https://www.rust-lang.org/
+[minidebconf]: https://wiki.debian.org/MiniDebConf

is->are
diff --git a/posts/time-real-time.mdwn b/posts/time-real-time.mdwn
index fbe43ce..b83d5a9 100644
--- a/posts/time-real-time.mdwn
+++ b/posts/time-real-time.mdwn
@@ -41,7 +41,7 @@ for people who have used that place for their time base.
 
 Rather than everywhere tracking what time it is,
 areas pick a common baseline and everyone in that area uses that time.
-This is called [Time Zones][] and are usually arranged along political lines.
+These are called [Time Zones][] and are usually arranged along political lines.
 
 In practice most computers think in terms of the [UTC][] time zone,
 and use records of what the difference in time is between the local time zone

publishing
diff --git a/posts/time-real-time.mdwn b/posts/time-real-time.mdwn
new file mode 100644
index 0000000..fbe43ce
--- /dev/null
+++ b/posts/time-real-time.mdwn
@@ -0,0 +1,120 @@
+[[!meta date="Wed, 30 Aug 2017 12:00:07 +0000"]]
+[[!meta title="Time - Real time"]]
+[[!meta author="Richard Maw"]]
+[[!tag time]]
+
+Up until now we've only considered time in relation to the machine we're using.
+
+This is only useful for recording events in the vicinity of that machine.
+
+To coordinate events happening elsewhere in the world
+such as it being [midday at Greenwich observatory][GMT],
+it is necessary to synchronise clocks.
+
+[GMT]: https://en.wikipedia.org/wiki/Greenwich_Mean_Time
+
+We've briefly introduced these concepts in our introduction to time,
+but more detail is warranted.
+
+## Real time
+
+"Real time" or "Wall clock time"
+is the globally coordinated time system,
+so if the time of an event is recorded in one location
+the record of that time can be transmitted elsewhere
+and they can reason about when this was in relation to their own clocks
+so they can tell how long ago it happened.
+
+This is handled by computers containing a special piece of hardware
+called a [Real-Time Clock][RTC]
+which tracks the current time.
+
+## Time Zones
+
+Times were historically defined by the position of the sun in the sky,
+but the sun is in different positions in the sky depending on where you are,
+so the coordinated time in any given location depends on where you are.
+
+If you pick any particular location for your definition of coordinated time,
+you need to know the difference in time from that location to elsewhere
+for people who have used that place for their time base.
+
+Rather than everywhere tracking what time it is,
+areas pick a common baseline and everyone in that area uses that time.
+This is called [Time Zones][] and are usually arranged along political lines.
+
+In practice most computers think in terms of the [UTC][] time zone,
+and use records of what the difference in time is between the local time zone
+and [UTC][].
+
+The difference is normally but not exclusively measured
+in an integral number of hours since that time in [UTC][].
+
+Indian standard time is 5½ hours after [UTC][].
+North Korea's time is 8½ hours after [UTC][].
+
+Time zones don't remain fixed.
+They are political entities so change on political decisions.
+
+Most of the western world observes some form of [Daylight saving time][DST]
+where the current time zone depends on what day of the year it is.
+
+This means some times do not exist in every time zone
+since the time zone is not defined for every part of the year.
+
+As a consequence some local times do not exist everywhere in the world,
+and the local time is a product of an agreed time in one part of the world,
+where the local time is being measured, and any political decisions.
+
+An extreme example of this is [Samoa skipping the 30th December 2011][samoa-tz]
+and jumping from one time zone to another.
+
+For future proofing you would ideally record the coordinates
+alongside the [UTC][] time
+so if a time zone's geopolitical boundaries change
+the local time at those coordinates may be known.
+
+[DST]: https://en.wikipedia.org/wiki/Daylight_saving_time
+[samoa-tz]: http://www.abc.net.au/news/2011-12-30/samoa-skips-friday-in-time-zone-change/3753350
+
+## Synchronisation
+
+Your computer's [RTC][] will continue to measure time while your computer is off
+so when you turn it back on the time is mostly correct.
+
+[RTCs][RTC] are not perfect however, they diverge from real time
+because they measure time slightly faster or slower.
+
+Handily, because computers are networked
+they can ask each other what the time actually is.
+The protocol for doing this is called [NTP][].
+
+Once a computer has determined the correct time
+it can use [adjtimex(2)][] to either accelerate or slow the clock until correct,
+or just set the time to what value it should have.
+
+It is preferable to speed or slow the clock to correct the time
+unless your computer is still early on in the boot process
+since you are likely to have programs that will get confused
+if the time changed a huge amount,
+but if your computer's clock is sufficiently far ahead or behind
+then it's impractical to accelerate or slow the clock to the correct time.
+
+Linux's interface to the real time is via the `CLOCK_REALTIME` clock,
+though `CLOCK_REALTIME_COARSE` exists if it's more important that
+the time is retrieved quickly rather than the result is precise.
+
+---
+
+Now that we've got a globally coordinated notion of time
+you can coordinate events globally.
+
+Unfortunately humans aren't trained to think in terms of position and [UTC][]
+so we need a way to translate this into something human readable,
+which will be the focus of the next article.
+
+[RTC]: https://en.wikipedia.org/wiki/Real-time_clock
+[Unix time]: https://en.wikipedia.org/wiki/Unix_time
+[UTC]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
+[NTP]: https://en.wikipedia.org/wiki/Network_Time_Protocol
+[adjtimex(2)]: http://man7.org/linux/man-pages/man2/adjtimex.2.html

Tweak four-years article
diff --git a/posts/four-years.mdwn b/posts/four-years.mdwn
index a3d9d7c..f250c01 100644
--- a/posts/four-years.mdwn
+++ b/posts/four-years.mdwn
@@ -21,10 +21,10 @@ Maw have contributed two each.  Jon Dowland has contributed one, and one of our
 articles was deliberately anonymously posted one Christmas.
 
 We've received thirty-eight comments spread over twenty-four of the articles.
-Our most prolific commenter has been Richard Ipsum, and otherwise they're
-spread relatively thinly among the approximately nineteen other commenters.
-A total of fifteen of the thirty-eight comments were by authors, usually in
-response to comments on their articles.
+Our most prolific commenters have been Gravious and Richard Maw; otherwise
+they're spread relatively thinly among the approximately nineteen other
+commenters.  More than fifteen of the thirty-eight comments were by authors,
+usually in response to comments on their articles.
 
 We have six items in our suggestion-box (thank you) though some are us
 acknowledging comments.  We're grateful for every suggestion and every bit of

Remove extra publishings
diff --git a/posts/moving-your-comfort-zone.mdwn b/posts/moving-your-comfort-zone.mdwn
deleted file mode 100644
index 9ebad58..0000000
--- a/posts/moving-your-comfort-zone.mdwn
+++ /dev/null
@@ -1,63 +0,0 @@
-[[!meta date="Tue, 22 Aug 2017 12:06:25 +0000"]]
-[[!meta title="Moving your comfort zone"]]
-[[!meta author="Daniel Silverstone"]]
-
-Over time, I've discussed with many people how they learn a new programming
-language.  A common theme is to write something you're intimately familiar with
-over again in a new language in order to learn and judge.  For example, some of
-my friends like to implement standard *NIX utilities such as `cat`, `echo`,
-`grep` etc.  Usually only trivial versions, but it gives them a feel for
-`stdio`, file access, command line argument processing, etc.  Some implement
-some kind of algorithmic solution to a known problem in order to get a good
-feel for control structures and approaches to data structures.  I am a little
-bit in both camps.  I tend to try and use controlled problems but I try not to
-reimplement things over and over.  Over-all any of these approaches are
-excellent in allowing the developer to gain an understanding of how a language
-works, and how to solve things in it.  Learning your tools is key to being an
-effective developer, and the language you're working in is one of those tools.
-
-Sometimes though, what you want to do is extend your knowledge in a different
-direction.  I am currently embarking on one such journey, and I'd like to tell
-you a little bit about it.
-
-I have, for many years, been interested in [microcontroller][]s, and writing
-software which works in severely [resource-limited environments][reslim] (such
-as a total of 20 kilobytes of [RAM][], or 128 kilobytes of program storage).
-I've been working with one such family of computing devices for quite a while
-now, and among my various projects I have developed [USB][] devices which do
-fun things such as monitor a bidirectional [serial][] link, providing
-millisecond timestamped transaction information down the USB port.  However
-throughout it all, USB itself has remained a fairly sealed black box.  I used
-libraries provided by the microcontroller vendor, and just programmed around
-them.
-
-While I was away [at a conference][debconf17] I decided though that this had to
-change.
-
-I decided there and then, that I would improve my understanding of several
-topics all at once.  I was going to learn more about the
-[microcontroller hardware][stm32], the specifics of USB itself, and improve my
-command of [a programming language][rustlang] all at once.  This is, as you
-might imagine, quite a tall order, but I feel that it's worth my while to push
-my comfort zone a little and do this.  To keep me honest, and to keep me
-working at this, I have also committed to presenting, at
-[a conference][minidebconf], some kind of results of my efforts.
-
-I tell this story here, in part to increase the assurance that there's plenty
-of people expecting me to do the work, and also in part to encourage you all to
-push your comfort zones a little.  Your homework, because of course there is
-some, is to think of something you do a lot, that you are comfortable,
-interested, and engaged with.  Now think of a way to twist that so that you
-learn a lot more about that topic while pushing your comfort zone just a little
-bit.  Why not comment below and tell me what you're going to do, and we can
-encourage one another just a little.
-
-[microcontroller]: https://en.wikipedia.org/wiki/Microcontroller
-[reslim]: https://en.wikipedia.org/wiki/Computational_resource
-[RAM]: https://en.wikipedia.org/wiki/Random-access_memory
-[USB]: https://en.wikipedia.org/wiki/USB
-[serial]: https://en.wikipedia.org/wiki/Serial_port
-[debconf17]: https://debconf17.debconf.org/
-[stm32]: https://en.wikipedia.org/wiki/STM32
-[rustlang]: https://www.rust-lang.org/
-[minidebconf]: https://wiki.debian.org/MiniDebConf
diff --git a/posts/time-real-time.mdwn b/posts/time-real-time.mdwn
deleted file mode 100644
index c0c6f7b..0000000
--- a/posts/time-real-time.mdwn
+++ /dev/null
@@ -1,120 +0,0 @@
-[[!meta date="Tue, 22 Aug 2017 12:03:25 +0000"]]
-[[!meta title="Time - Real time"]]
-[[!meta author="Richard Maw"]]
-[[!tag time]]
-
-Up until now we've only considered time in relation to the machine we're using.
-
-This is only useful for recording events in the vicinity of that machine.
-
-To coordinate events happening elsewhere in the world
-such as it being [midday at Greenwich observatory][GMT],
-it is necessary to synchronise clocks.
-
-[GMT]: https://en.wikipedia.org/wiki/Greenwich_Mean_Time
-
-We've briefly introduced these concepts in our introduction to time,
-but more detail is warranted.
-
-## Real time
-
-"Real time" or "Wall clock time"
-is the globally coordinated time system,
-so if the time of an event is recorded in one location
-the record of that time can be transmitted elsewhere
-and they can reason about when this was in relation to their own clocks
-so they can tell how long ago it happened.
-
-This is handled by computers containing a special piece of hardware
-called a [Real-Time Clock][RTC]
-which tracks the current time.
-
-## Time Zones
-
-Times were historically defined by the position of the sun in the sky,
-but the sun is in different positions in the sky depending on where you are,
-so the coordinated time in any given location depends on where you are.
-
-If you pick any particular location for your definition of coordinated time,
-you need to know the difference in time from that location to elsewhere
-for people who have used that place for their time base.
-
-Rather than everywhere tracking what time it is,
-areas pick a common baseline and everyone in that area uses that time.
-This is called [Time Zones][] and are usually arranged along political lines.
-
-In practice most computers think in terms of the [UTC][] time zone,
-and use records of what the difference in time is between the local time zone
-and [UTC][].
-
-The difference is normally but not exclusively measured
-in an integral number of hours since that time in [UTC][].
-
-Indian standard time is 5½ hours after [UTC][].
-North Korea's time is 8½ hours after [UTC][].
-
-Time zones don't remain fixed.
-They are political entities so change on political decisions.
-
-Most of the western world observes some form of [Daylight saving time][DST]
-where the current time zone depends on what day of the year it is.
-
-This means some times do not exist in every time zone
-since the time zone is not defined for every part of the year.
-
-As a consequence some local times do not exist everywhere in the world,
-and the local time is a product of an agreed time in one part of the world,
-where the local time is being measured, and any political decisions.
-
-An extreme example of this is [Samoa skipping the 30th December 2011][samoa-tz]
-and jumping from one time zone to another.
-
-For future proofing you would ideally record the coordinates
-alongside the [UTC][] time
-so if a time zone's geopolitical boundaries change
-the local time at those coordinates may be known.
-
-[DST]: https://en.wikipedia.org/wiki/Daylight_saving_time
-[samoa-tz]: http://www.abc.net.au/news/2011-12-30/samoa-skips-friday-in-time-zone-change/3753350
-
-## Synchronisation
-
-Your computer's [RTC][] will continue to measure time while your computer is off
-so when you turn it back on the time is mostly correct.
-
-[RTCs][RTC] are not perfect however, they diverge from real time
-because they measure time slightly faster or slower.
-
-Handily, because computers are networked
-they can ask each other what the time actually is.
-The protocol for doing this is called [NTP][].
-
-Once a computer has determined the correct time
-it can use [adjtimex(2)][] to either accelerate or slow the clock until correct,
-or just set the time to what value it should have.
-
-It is preferable to speed or slow the clock to correct the time
-unless your computer is still early on in the boot process
-since you are likely to have programs that will get confused
-if the time changed a huge amount,
-but if your computer's clock is sufficiently far ahead or behind
-then it's impractical to accelerate or slow the clock to the correct time.
-
-Linux's interface to the real time is via the `CLOCK_REALTIME` clock,
-though `CLOCK_REALTIME_COARSE` exists if it's more important that
-the time is retrieved quickly rather than the result is precise.
-
----
-
-Now that we've got a globally coordinated notion of time
-you can coordinate events globally.
-
-Unfortunately humans aren't trained to think in terms of position and [UTC][]
-so we need a way to translate this into something human readable,
-which will be the focus of the next article.
-
-[RTC]: https://en.wikipedia.org/wiki/Real-time_clock
-[Unix time]: https://en.wikipedia.org/wiki/Unix_time
-[UTC]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
-[NTP]: https://en.wikipedia.org/wiki/Network_Time_Protocol
-[adjtimex(2)]: http://man7.org/linux/man-pages/man2/adjtimex.2.html

publishing
diff --git a/posts/moving-your-comfort-zone.mdwn b/posts/moving-your-comfort-zone.mdwn
new file mode 100644
index 0000000..9ebad58
--- /dev/null
+++ b/posts/moving-your-comfort-zone.mdwn
@@ -0,0 +1,63 @@
+[[!meta date="Tue, 22 Aug 2017 12:06:25 +0000"]]
+[[!meta title="Moving your comfort zone"]]
+[[!meta author="Daniel Silverstone"]]
+
+Over time, I've discussed with many people how they learn a new programming
+language.  A common theme is to write something you're intimately familiar with
+over again in a new language in order to learn and judge.  For example, some of
+my friends like to implement standard *NIX utilities such as `cat`, `echo`,
+`grep` etc.  Usually only trivial versions, but it gives them a feel for
+`stdio`, file access, command line argument processing, etc.  Some implement
+some kind of algorithmic solution to a known problem in order to get a good
+feel for control structures and approaches to data structures.  I am a little
+bit in both camps.  I tend to try and use controlled problems but I try not to
+reimplement things over and over.  Over-all any of these approaches are
+excellent in allowing the developer to gain an understanding of how a language
+works, and how to solve things in it.  Learning your tools is key to being an
+effective developer, and the language you're working in is one of those tools.
+
+Sometimes though, what you want to do is extend your knowledge in a different
+direction.  I am currently embarking on one such journey, and I'd like to tell
+you a little bit about it.
+
+I have, for many years, been interested in [microcontroller][]s, and writing
+software which works in severely [resource-limited environments][reslim] (such
+as a total of 20 kilobytes of [RAM][], or 128 kilobytes of program storage).
+I've been working with one such family of computing devices for quite a while
+now, and among my various projects I have developed [USB][] devices which do
+fun things such as monitor a bidirectional [serial][] link, providing
+millisecond timestamped transaction information down the USB port.  However
+throughout it all, USB itself has remained a fairly sealed black box.  I used
+libraries provided by the microcontroller vendor, and just programmed around
+them.
+
+While I was away [at a conference][debconf17] I decided though that this had to
+change.
+
+I decided there and then, that I would improve my understanding of several
+topics all at once.  I was going to learn more about the
+[microcontroller hardware][stm32], the specifics of USB itself, and improve my
+command of [a programming language][rustlang] all at once.  This is, as you
+might imagine, quite a tall order, but I feel that it's worth my while to push
+my comfort zone a little and do this.  To keep me honest, and to keep me
+working at this, I have also committed to presenting, at
+[a conference][minidebconf], some kind of results of my efforts.
+
+I tell this story here, in part to increase the assurance that there's plenty
+of people expecting me to do the work, and also in part to encourage you all to
+push your comfort zones a little.  Your homework, because of course there is
+some, is to think of something you do a lot, that you are comfortable,
+interested, and engaged with.  Now think of a way to twist that so that you
+learn a lot more about that topic while pushing your comfort zone just a little
+bit.  Why not comment below and tell me what you're going to do, and we can
+encourage one another just a little.
+
+[microcontroller]: https://en.wikipedia.org/wiki/Microcontroller
+[reslim]: https://en.wikipedia.org/wiki/Computational_resource
+[RAM]: https://en.wikipedia.org/wiki/Random-access_memory
+[USB]: https://en.wikipedia.org/wiki/USB
+[serial]: https://en.wikipedia.org/wiki/Serial_port
+[debconf17]: https://debconf17.debconf.org/
+[stm32]: https://en.wikipedia.org/wiki/STM32
+[rustlang]: https://www.rust-lang.org/
+[minidebconf]: https://wiki.debian.org/MiniDebConf

publishing
diff --git a/posts/time-real-time.mdwn b/posts/time-real-time.mdwn
new file mode 100644
index 0000000..c0c6f7b
--- /dev/null
+++ b/posts/time-real-time.mdwn
@@ -0,0 +1,120 @@
+[[!meta date="Tue, 22 Aug 2017 12:03:25 +0000"]]
+[[!meta title="Time - Real time"]]
+[[!meta author="Richard Maw"]]
+[[!tag time]]
+
+Up until now we've only considered time in relation to the machine we're using.
+
+This is only useful for recording events in the vicinity of that machine.
+
+To coordinate events happening elsewhere in the world
+such as it being [midday at Greenwich observatory][GMT],
+it is necessary to synchronise clocks.
+
+[GMT]: https://en.wikipedia.org/wiki/Greenwich_Mean_Time
+
+We've briefly introduced these concepts in our introduction to time,
+but more detail is warranted.
+
+## Real time
+
+"Real time" or "Wall clock time"
+is the globally coordinated time system,
+so if the time of an event is recorded in one location
+the record of that time can be transmitted elsewhere
+and they can reason about when this was in relation to their own clocks
+so they can tell how long ago it happened.
+
+This is handled by computers containing a special piece of hardware
+called a [Real-Time Clock][RTC]
+which tracks the current time.
+
+## Time Zones
+
+Times were historically defined by the position of the sun in the sky,
+but the sun is in different positions in the sky depending on where you are,
+so the coordinated time in any given location depends on where you are.
+
+If you pick any particular location for your definition of coordinated time,
+you need to know the difference in time from that location to elsewhere
+for people who have used that place for their time base.
+
+Rather than everywhere tracking what time it is,
+areas pick a common baseline and everyone in that area uses that time.
+This is called [Time Zones][] and are usually arranged along political lines.
+
+In practice most computers think in terms of the [UTC][] time zone,
+and use records of what the difference in time is between the local time zone
+and [UTC][].
+
+The difference is normally but not exclusively measured
+in an integral number of hours since that time in [UTC][].
+
+Indian standard time is 5½ hours after [UTC][].
+North Korea's time is 8½ hours after [UTC][].
+
+Time zones don't remain fixed.
+They are political entities so change on political decisions.
+
+Most of the western world observes some form of [Daylight saving time][DST]
+where the current time zone depends on what day of the year it is.
+
+This means some times do not exist in every time zone
+since the time zone is not defined for every part of the year.
+
+As a consequence some local times do not exist everywhere in the world,
+and the local time is a product of an agreed time in one part of the world,
+where the local time is being measured, and any political decisions.
+
+An extreme example of this is [Samoa skipping the 30th December 2011][samoa-tz]
+and jumping from one time zone to another.
+
+For future proofing you would ideally record the coordinates
+alongside the [UTC][] time
+so if a time zone's geopolitical boundaries change
+the local time at those coordinates may be known.
+
+[DST]: https://en.wikipedia.org/wiki/Daylight_saving_time
+[samoa-tz]: http://www.abc.net.au/news/2011-12-30/samoa-skips-friday-in-time-zone-change/3753350
+
+## Synchronisation
+
+Your computer's [RTC][] will continue to measure time while your computer is off
+so when you turn it back on the time is mostly correct.
+
+[RTCs][RTC] are not perfect however, they diverge from real time
+because they measure time slightly faster or slower.
+
+Handily, because computers are networked
+they can ask each other what the time actually is.
+The protocol for doing this is called [NTP][].
+
+Once a computer has determined the correct time
+it can use [adjtimex(2)][] to either accelerate or slow the clock until correct,
+or just set the time to what value it should have.
+
+It is preferable to speed or slow the clock to correct the time
+unless your computer is still early on in the boot process
+since you are likely to have programs that will get confused
+if the time changed a huge amount,
+but if your computer's clock is sufficiently far ahead or behind
+then it's impractical to accelerate or slow the clock to the correct time.
+
+Linux's interface to the real time is via the `CLOCK_REALTIME` clock,
+though `CLOCK_REALTIME_COARSE` exists if it's more important that
+the time is retrieved quickly rather than the result is precise.
+
+---
+
+Now that we've got a globally coordinated notion of time
+you can coordinate events globally.
+
+Unfortunately humans aren't trained to think in terms of position and [UTC][]
+so we need a way to translate this into something human readable,
+which will be the focus of the next article.
+
+[RTC]: https://en.wikipedia.org/wiki/Real-time_clock
+[Unix time]: https://en.wikipedia.org/wiki/Unix_time
+[UTC]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
+[NTP]: https://en.wikipedia.org/wiki/Network_Time_Protocol
+[adjtimex(2)]: http://man7.org/linux/man-pages/man2/adjtimex.2.html

publishing
diff --git a/posts/four-years.mdwn b/posts/four-years.mdwn
new file mode 100644
index 0000000..a3d9d7c
--- /dev/null
+++ b/posts/four-years.mdwn
@@ -0,0 +1,47 @@
+[[!meta date="Tue, 22 Aug 2017 12:00:08 +0000"]]
+[[!meta title="Four years of chinwaggery"]]
+[[!meta author="Daniel Silverstone"]]
+
+Four years ago, Lars posted [[our first article|software-freedom-concepts]] on
+software freedom.  This started an epic effort to help educate those who want
+to get into free-software.  We pledged to discuss technical topics such as
+[[shell|tags/shell]] and [[C|tags/C]], and non-technical topics such as
+[[diversity|tags/diversity]] and [[motivation|tags/motivation]].  Through our
+time we've had opinionated series on [[the truisms of software|tags/truism]],
+or strong technical sets around topics such as [[systemd|tags/systemd]].
+
+---
+
+To give you some numbers, in the past four years we've published two hundred
+and eleven (or two hundred and twelve if you include this one) articles, by
+seven authors.  Eighty-three were by Richard Maw, seventy-four (seventy-five)
+by yours truly, and forty-one by Lars Wirzenius.  Our most prolific guest
+author was Will Holland who has contributed seven, Richard Ipsum and Jonathan
+Maw have contributed two each.  Jon Dowland has contributed one, and one of our
+articles was deliberately anonymously posted one Christmas.
+
+We've received thirty-eight comments spread over twenty-four of the articles.
+Our most prolific commenter has been Richard Ipsum, and otherwise they're
+spread relatively thinly among the approximately nineteen other commenters.
+A total of fifteen of the thirty-eight comments were by authors, usually in
+response to comments on their articles.
+
+We have six items in our suggestion-box (thank you) though some are us
+acknowledging comments.  We're grateful for every suggestion and every bit of
+encouragement you've provided over the years, via the site, IRC, Twitter, etc.
+
+---
+
+Over the years, our core contributors have had their own ups and downs, and yet
+we've pretty much managed to get an article out every week no matter
+what. Indeed we missed one week (I believe) in all that time, and that was
+because we typoed the date in our publishing queue, and none of us caught it in
+review.  Sadly, it gets harder and harder though, and so please do pop over to
+the suggestion box if there're topics you'd like to see us cover (even if you
+just want an expansion of something we've previously discussed).  Perhaps come
+and join us in `#yakking` on the OFTC IRC network, and if you're feeling very
+enthusiastic then come and discuss guest-posting since we're always grateful
+for contributions.
+
+Here's to another four years of articles which you consider worth reading…
+

Added a comment: Re: splice and portability
diff --git a/posts/moving-files-3-faster/comment_2_9640d160f32196a7530eb5d7f90f6935._comment b/posts/moving-files-3-faster/comment_2_9640d160f32196a7530eb5d7f90f6935._comment
new file mode 100644
index 0000000..01d9615
--- /dev/null
+++ b/posts/moving-files-3-faster/comment_2_9640d160f32196a7530eb5d7f90f6935._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="http://richard.maw.name/"
+ nickname="Richard Maw"
+ avatar="http://cdn.libravatar.org/avatar/4d312a0989b085a9dfa9ba61d60da130979b9c408659132fea11d5efe2c90fc5"
+ subject="Re: splice and portability"
+ date="2017-08-21T10:13:11Z"
+ content="""
+Yeah, splice is included because at the time I had the notion of writing a generic copy routine between two file descriptors.
+
+We're assuming Linux, but with some flexibility of which version.
+
+*   sendfile was introduced in Linux 2.2, but the output file descriptor must be a socket. Since 2.6.33 it may be any file.
+*   splice was introduced in Linux 2.6.17 and might some day support any file descriptor.
+*   `copy_file_range` was introduced in Linux 4.5
+
+Checking versions would be inappropriate since you see frankenkernels where newer features have been back-ported, and sometimes system calls are optional, depending on kernel configuration, such as `name_to_handle_at`.
+"""]]

Added a comment: Re: article suggestion: Handling a signal correctly
diff --git a/suggestion-box/comment_6_465e2be641f88aea55735c478904977a._comment b/suggestion-box/comment_6_465e2be641f88aea55735c478904977a._comment
new file mode 100644
index 0000000..26d3f8e
--- /dev/null
+++ b/suggestion-box/comment_6_465e2be641f88aea55735c478904977a._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="http://richard.maw.name/"
+ nickname="Richard Maw"
+ avatar="http://cdn.libravatar.org/avatar/4d312a0989b085a9dfa9ba61d60da130979b9c408659132fea11d5efe2c90fc5"
+ subject="Re: article suggestion: Handling a signal correctly"
+ date="2017-08-21T08:43:18Z"
+ content="""
+Sure thing. I'll add it to my \"To write\" queue after I'm finished with time.
+"""]]

Added a comment: article suggestion: Handling a signal correctly
diff --git a/suggestion-box/comment_5_287af6179c98a3730952918cf11f5a94._comment b/suggestion-box/comment_5_287af6179c98a3730952918cf11f5a94._comment
new file mode 100644
index 0000000..5d68fb3
--- /dev/null
+++ b/suggestion-box/comment_5_287af6179c98a3730952918cf11f5a94._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="Gravious"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="article suggestion: Handling a signal correctly"
+ date="2017-08-19T13:53:00Z"
+ content="""
+There's a lot of guides out there on how to correctly handle a signal,
+seems like the kind of topic this blog would cover nicely,
+maybe include the following point? which seems to be missed in examples I've seen.
+
+ftp://ftp.gnu.org/old-gnu/Manuals/glibc-2.2.3/html_chapter/libc_24.html#SEC488
+"""]]

Comment moderation
diff --git a/posts/moving-files-3-faster/comment_1_41bf6b8f220ba4a3325479618517be41._comment b/posts/moving-files-3-faster/comment_1_41bf6b8f220ba4a3325479618517be41._comment
new file mode 100644
index 0000000..8e36c09
--- /dev/null
+++ b/posts/moving-files-3-faster/comment_1_41bf6b8f220ba4a3325479618517be41._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="Gravious"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="splice and portability"
+ date="2017-02-26T18:55:58Z"
+ content="""
+Pretty cool stuff!
+
+Two things occur to me though, the first is that according to my man page, for splice(2) to be applicable one of the fds has to be a pipe, which probably rules it out for file copying. The second is that none of these calls seem to be standard, they're linux specific and my man pages here suggest that prototypes and semantics differ across platforms such that these calls can't be used portably. This makes me wonder whether ENOSYS is really useful here, since if we write code using these calls then we're already presumably tied to a particular platform (linux), so we can safely assume these calls are implemented?
+"""]]

Added a comment: Privilege, Facility, and other terms
diff --git a/posts/taking-time-for-yourself/comment_4_15286ea0d82fe8fbe189f6dc1c166f38._comment b/posts/taking-time-for-yourself/comment_4_15286ea0d82fe8fbe189f6dc1c166f38._comment
new file mode 100644
index 0000000..3a311a2
--- /dev/null
+++ b/posts/taking-time-for-yourself/comment_4_15286ea0d82fe8fbe189f6dc1c166f38._comment
@@ -0,0 +1,89 @@
+[[!comment format=mdwn
+ username="http://www.digital-scurf.org/"
+ nickname="Daniel Silverstone"
+ avatar="http://cdn.libravatar.org/avatar/914439e9dd6721b44b2ea9039fef830f5c6f7d3b6adfceb9e41b62be82e9707f"
+ subject="Privilege, Facility, and other terms"
+ date="2017-08-17T19:53:05Z"
+ content="""
+> I don't follow, are people privileged to be able to paint their garden shed a
+> new colour at the weekend? Or write poetry in their free time? Or watch game
+> of thrones in the evening?
+
+Most of these are examples of the privilege of having sufficient money to afford
+the materials and services required to do this (though I'll admit writing poetry
+likely requires the least in terms of material investment).
+
+> Or isn't that just a pretty standard expectation of what anyone can do in
+> western society? Why do you think hacking on foss is some special privilege
+> vs these other things?
+
+It's a 'pretty standard expectation' for people in my (and perhaps your)
+situation.  People who are, to whatever extent, lucky (or whatever term you'd
+prefer to use) enough to have free time (not a given), sufficient money (not a
+given), sufficient space (not a given), and sufficient spoons (read about
+[spoon theory][] if this isn't a term you're familiar with).
+
+[spoon theory]: https://en.wikipedia.org/wiki/Spoon_theory
+
+> I've written quite a bit of code in my free time, and I have to be honest with
+> you, I don't really consider it a privilege to lock myself in a room at the
+> weekend and bang out code,
+
+It means you are privileged enough to have free time, a computer to 'bang out
+code' on, the room in which to do that, the language facilities to understand
+enough about what you're doing to be able to do that, the good fortune to have
+had an education which enables you to understand and do it at all, and the
+mental fortitude and energy to do that in the first place.
+
+> it's something I do mostly cause the way I look precludes me being able to
+> date pretty ladies (let's just be honest here). I mean I enjoy it too, but I
+> suspect that's due to me not being able to spend much time with the pretty
+> ladies.
+
+I'm not touching this, I'm not in a position to discuss this kind of topic.
+
+> Also, why do you think you need money? The code I've produced over the years
+> cost me exactly $0 to make,
+
+So you've never had to pay for the accomodation you used while coding?  The
+food you burned up in the process?  The computer on which you did the work?
+(And if you're using a computer provided by a workplace then I count that since
+it's a form of remuneration to be permitted to do personal activities with a
+work resource)  Perhaps you haven't ever had to pay for any of that, in which
+case you simply had a financial privilege not afforded to a huge number of
+people who might otherwise be capable of doing FOSS work if they had been
+afforded similar.
+
+> maybe your argument is that I'm middle class or something and so have the
+> time, that's true, I am afforded that, but pretty much all people in a
+> western society have some time for these things, not as much as they should
+> by the way, but that's another story.
+
+I think you're massively overestimating the time, money, capability, spoons,
+etc, available to the average member of \"western society\".  Also I was trying to speak in
+general, not just of \"western society\" which is an artificial narrowing of the
+scope of the discussion, though one I can understand since you seek to
+comprehend from the perspective of your lived experience.
+
+> And I don't really get what you mean by \"facility\" either to be honest...
+
+Again I apologise, I thought it was clear that \"facility\" in this context meant
+access to computer resources, a lack of language barrier with respect to
+learning and participating in F/LOSS communities, a capability in a social
+sense to participate, and indeed an environment which is conducive to the act
+of producing software in the first place.
+
+While this dicussion is interesting to me, I kinda feel like this isn't the
+right forum to continue it.  I also don't feel that I'm necessarily the right
+person to attempt to widen your perspective on this (or indeed that I'm
+necessarily *right* to be trying to do so).  I ask that you consider any
+questions posed in this response as rhetorical rather than as an attempt to
+elicit a response and, unless you have a comment about another aspect of the
+article, that you drop this line of discussion for now.  Perhaps another
+article will be posted in the future which you can engage on this topic with in
+a more productive fashion.
+
+Thank you for engaging with me on this, I think this comment thread will provide
+a good reference for others who want to understand more about this topic area.
+
+"""]]

Added a comment: i don't follow
diff --git a/posts/taking-time-for-yourself/comment_3_2ea53b3a558f78ed9ad5b97edc9aecf0._comment b/posts/taking-time-for-yourself/comment_3_2ea53b3a558f78ed9ad5b97edc9aecf0._comment
new file mode 100644
index 0000000..a6bdc36
--- /dev/null
+++ b/posts/taking-time-for-yourself/comment_3_2ea53b3a558f78ed9ad5b97edc9aecf0._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="Gravious"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="i don't follow"
+ date="2017-08-17T16:37:03Z"
+ content="""
+I don't follow, are people privileged to be able to paint their garden shed a new colour at the weekend? Or write poetry in their free time? Or watch game of thrones in the evening? Or isn't that just a pretty standard expectation of what anyone can do in western society? Why do you think hacking on foss is some special privilege vs these other things?
+
+I've written quite a bit of code in my free time, and I have to be honest with you, I don't really consider it a privilege to lock myself in a room at the weekend and bang out code, it's something I do mostly cause the way I look precludes me being able to date pretty ladies (let's just be honest here). I mean I enjoy it too, but I suspect that's due to me not being able to spend much time with the pretty ladies.
+
+Also, why do you think you need money? The code I've produced over the years cost me exactly $0 to make,
+maybe your argument is that I'm middle class or something and so have the time, that's true,
+I am afforded that, but pretty much all people in a western society have *some* time for these things,
+not as much as they should by the way, but that's another story.
+
+And I don't really get what you mean by \"facility\" either to be honest...
+"""]]

Move the tags out of the sidebar, they're too numerous
diff --git a/sidebar.mdwn b/sidebar.mdwn
index 50cd19a..4a4f972 100644
--- a/sidebar.mdwn
+++ b/sidebar.mdwn
@@ -12,8 +12,7 @@
 
 [[Suggestion box|suggestion-box]]
 
-[[Tags]]:
-[[!pagestats style="list" pages="./tags/*" among="./posts/*"]]
+[[Tags]]
 
 ---
 
diff --git a/tags.mdwn b/tags.mdwn
index 8e05059..507124c 100644
--- a/tags.mdwn
+++ b/tags.mdwn
@@ -1,5 +1,7 @@
 [[!meta title="Yakking tag cloud"]]
 
-[[!pagestats pages="./tags/*" among="./posts/*"]]
+Below is a tag list:
 
-On the right you can see the tag cloud for this blog.
+[[!pagestats pages="./tags/*" among="./posts/*" style="table"]]
+
+<!-- [[!pagestats style="list" pages="./tags/*" among="./posts/*"]] -->

Added a comment: Perhaps a poor choice of words
diff --git a/posts/taking-time-for-yourself/comment_2_b542ef6e507f572364affaf0eda755d9._comment b/posts/taking-time-for-yourself/comment_2_b542ef6e507f572364affaf0eda755d9._comment
new file mode 100644
index 0000000..4c456de
--- /dev/null
+++ b/posts/taking-time-for-yourself/comment_2_b542ef6e507f572364affaf0eda755d9._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="http://www.digital-scurf.org/"
+ nickname="Daniel Silverstone"
+ avatar="http://cdn.libravatar.org/avatar/914439e9dd6721b44b2ea9039fef830f5c6f7d3b6adfceb9e41b62be82e9707f"
+ subject="Perhaps a poor choice of words"
+ date="2017-08-17T13:54:38Z"
+ content="""
+Perhaps
+
+> Sadly, those of us who are blessed with the ability and the interest in contributing to F/LOSS tend to work hard, and then effectively \"work as play\" hard too
+
+was a poor choice of words.  The sense I was trying to get across was **not** that the ability to write code at all is something one gets blessed with, but more that some of are _privileged enough_ to able to work on F/LOSS in our time, off our own backs, with our own money.  In other words, that we have the _richness of time and energy_ to work on F/LOSS.  I feel in some sense blessed that I'm part of the tranche of society which has enough money, time, and facility to do this.
+
+I trust that clarifies things for you.
+"""]]

Added a comment: "blessed with ability"
diff --git a/posts/taking-time-for-yourself/comment_1_34d2e8e5a908ade45dd1a56e06d02b2c._comment b/posts/taking-time-for-yourself/comment_1_34d2e8e5a908ade45dd1a56e06d02b2c._comment
new file mode 100644
index 0000000..a8ad19e
--- /dev/null
+++ b/posts/taking-time-for-yourself/comment_1_34d2e8e5a908ade45dd1a56e06d02b2c._comment
@@ -0,0 +1,28 @@
+[[!comment format=mdwn
+ username="Gravious"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="&quot;blessed with ability&quot;"
+ date="2017-08-17T09:19:53Z"
+ content="""
+\"Sadly, those of us who are blessed with the ability and the interest in contributing to F/LOSS\"
+
+I don't think this is done intentionally, but you seem to be suggesting
+that programming is an ability some people are blessed with, at least
+that's my interpretation of the above.
+
+I profoundly disagree with that notion, and know it to be false through
+personal experience of working with people with no prior programming experience.
+The truth is there is really no special ability required, saying there is is akin
+to what the intellectuals of the late 19th century were saying about literature.
+
+Those intellectuals essentially responded to mass education by obfuscating
+literature and art so that only they could understand it. I see the same
+thing happening when people sneer at languages like Ruby that aim to make
+things just a bit easier. It's a mirror image of the intellectuals sneering
+at popular literature.
+
+_why understood this, and wrote the poignant guide in response. It is maybe
+slightly ironic, given folk's apparent perception of me as someone who is
+against equality that I am now bringing this argument here.
+
+"""]]

publishing
diff --git a/posts/taking-time-for-yourself.mdwn b/posts/taking-time-for-yourself.mdwn
new file mode 100644
index 0000000..580898c
--- /dev/null
+++ b/posts/taking-time-for-yourself.mdwn
@@ -0,0 +1,31 @@
+[[!meta date="Wed, 16 Aug 2017 12:00:06 +0000"]]
+[[!meta title="Taking time for yourself"]]
+[[!meta author="Daniel Silverstone"]]
+
+[Occupational Burnout][] is a thing which people worry about a lot in the "real
+world" and it's why we encourage people, particularly information workers, to
+take regular breaks, to not think about their job outside of work.  Indeed,
+burnout has been referred to as a [disease][] and as such we recommend strongly
+that you avoid it.
+
+Sadly, those of us who are blessed with the ability and the interest in
+contributing to F/LOSS tend to work hard, and then effectively "work as play"
+hard too; which can lead to burning out even more quickly.  It can be even
+worse when the stress originates in your F/LOSS activity because it can be seen
+as making your 'funtime' less enjoyable.
+
+Burning out is a leading cause of people having to [[retire|retiring]] from
+F/LOSS projects and as such, it's really important that you know when to step
+away from F/LOSS and have a break.  You might prefer to spend a few days
+entirely away from your computer or just spend it immersed in a game.  If
+you're particularly lucky/unlucky then you might just be able to work on a
+different project for a little while instead.  Whatever you do to relax, be
+sure to increase your explicit relaxation time along with time you're spending
+on F/LOSS to keep yourself happy and healthy, and able to contribute for a nice
+long time to come.
+
+Your homework this week is to just think about what you enjoy doing which isn't
+work or F/LOSS related at all, and go do it.  Just shoo!
+
+[Occupational Burnout]: https://en.wikipedia.org/wiki/Occupational_burnout
+[disease]: http://www.huffingtonpost.com/arianna-huffington/burnout-third-metric_b_3792354.html

Added a comment: nice
diff --git a/posts/converting-to-argp/comment_1_eb5075d43959b7913afb74cd523db9bf._comment b/posts/converting-to-argp/comment_1_eb5075d43959b7913afb74cd523db9bf._comment
new file mode 100644
index 0000000..380ddec
--- /dev/null
+++ b/posts/converting-to-argp/comment_1_eb5075d43959b7913afb74cd523db9bf._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Gravious"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="nice"
+ date="2017-08-09T21:22:36Z"
+ content="""
+nice article thanks :D
+"""]]

publishing
diff --git a/posts/retiring.mdwn b/posts/retiring.mdwn
new file mode 100644
index 0000000..9f6fdc8
--- /dev/null
+++ b/posts/retiring.mdwn
@@ -0,0 +1,42 @@
+[[!meta date="Wed, 09 Aug 2017 12:00:08 +0000"]]
+[[!meta title="Retiring from a project"]]
+[[!meta author="Lars Wirzenius"]]
+
+Sometimes you'll want to leave a free software project. It might be
+one you founded or one you've joined. You may have spent years
+contributing to it. You may have formed friendships with other
+contributors: working together on something for a long time tends to
+be a catalyst for that. However, things change and you may want to
+leave. You might no longer be using the software. You might not have
+time to contribute. There might be disagreements about where the
+project is going or how it is going to be operating. You might be moving to
+a different continent. You may be switching careers entirely. You may
+be founding an unrelated company.
+
+A term for this is 'retiring'. Depending on the project, there
+may be a processs to follow, or you may just wing it.
+
+More importantly, there're various aspects to consider when retiring,
+especially if you've been involved for a long time.
+
+* Why are you leaving? It's best to be honest about this, particularly
+  to yourself. Don't rage quit.
+* Will the project survive you leaving?
+* How will users of the software be affected?
+* What about other collaborators on the project?
+* Will there be people to pick up the slack and take over
+  responsibilities? Will they know what to do? Can they ask you for
+  help afterwards?
+* Is there any publicity likely to follow from the retirement?
+  (Probably not, except for high-profile projects.)
+* Are there any assets (computers, etc) that need to be dealt with?
+
+Retiring from a free software project is a lot like leaving paid
+employment. If you do it well, you make sure all your old commitments
+and responsibilities are handed over to new people, and no-one is
+affected too adversely from the change. As a result, you'll be
+remembered with fondness and you're always welcome back.
+
+Unlike paid employment, there's few hard and fast rules in Free Software. It's
+important to remember that though your contributions are valued, you're not
+obliged to continue them if you don't want to.

publishing
diff --git a/posts/my-floss-activity.mdwn b/posts/my-floss-activity.mdwn
new file mode 100644
index 0000000..b80ccfd
--- /dev/null
+++ b/posts/my-floss-activity.mdwn
@@ -0,0 +1,26 @@
+[[!meta date="Wed, 02 Aug 2017 12:00:07 +0000"]]
+[[!meta title="My F/LOSS Activity..."]]
+[[!meta author="Daniel Silverstone"]]
+
+There has been a growing trend among bloggers, particularly among those
+aggregated on [Planet Debian][], in which the blogger writes regularly (usually
+monthly) about their activity in the Free Software communities since their last
+report.
+
+This can be used as a way to "keep yourself honest" in the sense that if you're
+committed to reporting your activity on a month by month basis, you kinda need
+some activity to report.  It can be used as a way to keep your colleagues and
+co-conspiritors in F/LOSS informed about what you're working on, and cool
+things you've done which they might be interested in.  It might be a useful way
+to motivate yourself when each period of time you get to write a nice blog
+posting all about the wonderful things you've achieved and the projects you've
+improved along the way.
+
+Recently I've been persuaded to [join the trend][] and I'm looking forward to
+experiencing the effects I've mentioned above.  I'd like to suggest that all of
+you go out and write yourself a blog post all about the wonderful things you've
+done and then commit yourself to doing so again in X amount of time in the
+future.
+
+[Planet Debian]: http://planet.debian.org/
+[join the trend]: https://blog.digital-scurf.org/posts/floss-activity-2017-06/

Fix typo, thanks mafm
diff --git a/posts/open-data-formats.mdwn b/posts/open-data-formats.mdwn
index a182653..dd31ae3 100644
--- a/posts/open-data-formats.mdwn
+++ b/posts/open-data-formats.mdwn
@@ -14,7 +14,7 @@ amount of pain.  This drove home to me once more that the format of input and
 output of data is such a critical part of software tooling that it must weigh
 as heavily as, or perhaps even more heavily than, the software's functionality.
 
-As [Tannenbaum][] tells us, the great thing about standards is that there's so
+As [Tanenbaum][] tells us, the great thing about standards is that there's so
 many of them to choose from. [XKCD][] tells us, [how that comes about][tgtas].
 Data formats are many and varied, and suffer from specifications as vague as
 "plain text" to things as complex as the structure of data stored in custom
@@ -49,6 +49,6 @@ projects and check that their input and output data formats are well documented
 if appropriate.
 
 [XML]: https://en.wikipedia.org/wiki/XML
-[Tannenbaum]: http://www.goodreads.com/quotes/589703-the-good-thing-about-standards-is-that-there-are-so
+[Tanenbaum]: http://www.goodreads.com/quotes/589703-the-good-thing-about-standards-is-that-there-are-so
 [XKCD]: https://xkcd.com/
 [tgtas]: https://xkcd.com/927/

Correct a corectable
diff --git a/posts/time-adjustment.mdwn b/posts/time-adjustment.mdwn
index 35897d7..318c3b0 100644
--- a/posts/time-adjustment.mdwn
+++ b/posts/time-adjustment.mdwn
@@ -24,7 +24,7 @@ by using the [adjtimex(2)][] or [clock_adjtime(2)][] system calls.
 This can't be done with `CLOCK_MONOTONIC_RAW`,
 but can be done with `CLOCK_MONOTONIC`.
 
-In addition to being corectable,
+In addition to being correctable,
 `CLOCK_MONOTONIC` can be used with [clock_nanosleep(2)][].
 
 This will allow you to sleep for at least the period of time specified,

creating tag page tags/ntp
diff --git a/tags/ntp.mdwn b/tags/ntp.mdwn
new file mode 100644
index 0000000..6e70f03
--- /dev/null
+++ b/tags/ntp.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged ntp"]]
+
+[[!inline pages="tagged(ntp)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/time-adjustment.mdwn b/posts/time-adjustment.mdwn
new file mode 100644
index 0000000..35897d7
--- /dev/null
+++ b/posts/time-adjustment.mdwn
@@ -0,0 +1,62 @@
+[[!meta date="Wed, 26 Jul 2017 12:00:07 +0000"]]
+[[!meta title="Time - Adjustment"]]
+[[!meta author="Richard Maw"]]
+[[!tag time clock ntp]]
+
+`CLOCK_MONOTONIC_RAW` reflects the underlying hardware for measuring time.
+
+In the short term this is mostly correct,
+but hardware isn't perfect,
+so it can, over long periods, drift
+and no longer be synchronised with
+what the rest of the world considers the time to be.
+
+If you know what the time is meant to be elsewhere in the world,
+then you can adjust your clock to correct it.
+
+Typically your computer will do this
+with the [Network Time Protocol, or NTP,][NTP],
+by asking trusted computers on the internet what the time is.
+
+Actually correcting the time works
+by using the [adjtimex(2)][] or [clock_adjtime(2)][] system calls.
+
+This can't be done with `CLOCK_MONOTONIC_RAW`,
+but can be done with `CLOCK_MONOTONIC`.
+
+In addition to being corectable,
+`CLOCK_MONOTONIC` can be used with [clock_nanosleep(2)][].
+
+This will allow you to sleep for at least the period of time specified,
+though could be interrupted when a signal is delivered,
+(which could happen with [timer_create(2)][]).
+
+## Similar clocks
+
+If it's more important to get the time quickly,
+than to get a more precise time,
+such as if you're profiling real-time software and want to not slow it down,
+then you can use `CLOCK_MONOTONIC_COARSE`.
+
+`CLOCK_MONOTONIC` can be used to time events,
+but works by counting seconds while the computer is running.
+This could be a problem if your computer suspends,
+since then it would stop counting.
+
+The solution to this is the `CLOCK_BOOTTIME` clock,
+which will include seconds spent suspended,
+so could be used to time external events.
+
+---
+
+So far everything discussed has been somewhat abstract,
+divorced from what we commonly understand to be time.
+
+This will be rectified in the next article in the time series,
+where we will be covering "real time".
+
+[NTP]: https://en.wikipedia.org/wiki/NTP
+[adjtimex(2)]: http://man7.org/linux/man-pages/man2/adjtimex.2.html
+[clock_adjtime(2)]: http://man7.org/linux/man-pages/man2/clock_adjtime.2.html
+[clock_nanosleep(2)]: http://man7.org/linux/man-pages/man2/clock_nanosleep.2.html
+[timer_create(2)]: http://man7.org/linux/man-pages/man2/timer_create.2.html

publishing
diff --git a/posts/what-and-why-nix.mdwn b/posts/what-and-why-nix.mdwn
new file mode 100644
index 0000000..57a6dbe
--- /dev/null
+++ b/posts/what-and-why-nix.mdwn
@@ -0,0 +1,140 @@
+[[!meta date="Wed, 19 Jul 2017 12:00:07 +0000"]]
+[[!meta title="What is Nix and Why you should try it!"]]
+[[!meta author="Richard Ipsum"]]
+
+Normally our Unix systems organise the file system in a structure
+called the Filesystem Hierarchy Standard (FHS).
+Installing into an FHS has limitations, what would happen if we want to install,
+for example, two different versions of ruby at the same time?
+Typically this isn't possible without explicitly specifying a
+separate installation directory, if we just install to the usual
+place e.g. `/usr/bin` then we will just overwrite the previous ruby.
+So perhaps we would install one ruby into `/usr/bin` and another into
+`/usr/local/bin`, this is fine, but what about dependent libs?
+Assuming the two different versions of ruby do require different
+dependencies then we have potentially the same problem that
+the dependencies for the 1st ruby might overwrite the dependencies
+for the 2nd ruby.
+
+Nix gets around this to some extent by not using FHS, instead nix installs
+all files into the nix store, which is usually located at `/nix/store`.
+All programs in a nix store are identified by their store path, which
+is uniquely generated for each distinct nix package. As a result of this,
+different versions of the same ruby no longer conflict because they are
+each assigned their own locations within the nix store.
+
+To enable use of programs within the store, nix maintains an environment
+which is basically a mapping of FHS path `->`
+nix store path, where the `->` is a symlink. So for example, let's first install
+ruby 2.0 into our environment
+
+    nix@salo:~$ nix-env -f nixpkgs -iA pkgs.ruby_2_0
+    installing ‘ruby-2.0.0-p648’
+    these paths will be fetched (3.43 MiB download, 19.35 MiB unpacked):
+      /nix/store/bxm4s71qdyh071ap5ywxc63aja62cbyc-gdbm-1.13
+      /nix/store/d2ccapssrq683rj0fr7d7nb3ichxvlsy-ruby-2.0.0-p648
+      /nix/store/h85k47l9zpwwxdsn9kkjmqw8pnfnrwmm-libffi-3.2.1
+      /nix/store/zj8cjx71sqvv46sxfggjpdzqz6nss047-libyaml-0.1.7
+    fetching path ‘/nix/store/bxm4s71qdyh071ap5ywxc63aja62cbyc-gdbm-1.13’...
+    ....
+    building path(s) ‘/nix/store/j649f78ha04mi1vykz601b00ml3qlr9q-user-environment’
+    created 419 symlinks in user environment
+
+we can see the symlink that was just created to our ruby2.0 in the store,
+
+	nix@salo:~$ ls -l $(which irb)
+	lrwxrwxrwx 1 nix nix 67 Jan  1  1970 /home/nix/.nix-profile/bin/irb -> /nix/store/d2ccapssrq683rj0fr7d7nb3ichxvlsy-ruby-2.0.0-p648/bin/irb
+
+	nix@salo:~$ irb
+	irb(main):001:0> puts RUBY_VERSION
+	2.0.0
+
+as you can see we're only able to execute the interactive ruby prompt `irb`
+because it's symlinked into our environment which is, of course, on the `$PATH`,
+
+	nix@salo:~$ echo $PATH
+	/home/nix/.nix-profile/bin:/home/nix/.nix-profile/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
+
+to prove the point about multiple versions on the same system let's swap
+ruby 2.0 for ruby 2.4
+
+	nix@salo:~$ nix-env -f nixpkgs -iA pkgs.ruby_2_4
+	replacing old ‘ruby-2.0.0-p648’
+	installing ‘ruby-2.4.1’
+	these paths will be fetched (3.13 MiB download, 15.32 MiB unpacked):
+	  /nix/store/48xrfkanmx5sshqj1364k2dw25xr4znj-ruby-2.4.1
+	fetching path ‘/nix/store/48xrfkanmx5sshqj1364k2dw25xr4znj-ruby-2.4.1’...
+	...
+	*** Downloading ‘https://cache.nixos.org/nar/00hh9w9nvlbinya1i9j0v7v89pw3zzlrfqps72441k7p2n8zq7d3.nar.	xz’ to ‘/nix/store/48xrfkanmx5sshqj1364k2dw25xr4znj-ruby-2.4.1’...
+	  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
+	                                 Dload  Upload   Total   Spent    Left  Speed
+	100 3205k  100 3205k    0     0   114k      0  0:00:27  0:00:27 --:--:--  125k
+	
+	building path(s) ‘/nix/store/7b2mmk2ffmy1c2bxq7r6y9cn6r0nwn8s-user-environment’
+	created 415 symlinks in user environment
+
+	nix@salo:~$ ls -l $(which irb)
+	lrwxrwxrwx 1 nix nix 62 Jan  1  1970 /home/nix/.nix-profile/bin/irb -> /nix/store/48xrfkanmx5sshqj1364k2dw25xr4znj-ruby-2.4.1/bin/irb
+
+	nix@salo:~$ irb
+	irb(main):001:0> puts RUBY_VERSION
+	2.4.1
+
+You may be wondering whether this is really an improvement, since although
+we have multiple versions of the same package installed on our system,
+we can only have one `ruby` in the environment at any one time. To deal
+with this nix provides the nix-shell utility which constructs an environment
+on demand and runs a new shell based on that environment.
+
+	nix@salo:~/nixpkgs$ nix-shell -p ruby_2_0            
+	these paths will be fetched (4.44 MiB download, 22.57 MiB unpacked):
+	  /nix/store/2l8irkrhvdqmd1h96pcnwv0832p9r901-libffi-3.2.1
+	  /nix/store/945sd3dbynzpkqdd71cqqpsl8gwi9zsq-ruby-2.0.0-p647
+	  /nix/store/m74m7c4qbzml7ipfxzlpxddcn9ah8jrs-gdbm-1.12
+	  /nix/store/zbjyc3ylb9bj3057rk5payv3sr0gnmkc-openssl-1.0.2l
+	  /nix/store/zsgmhsc8pjx9cisbjdk06qqjm8h89lmp-libyaml-0.1.7
+	fetching path ‘/nix/store/m74m7c4qbzml7ipfxzlpxddcn9ah8jrs-gdbm-1.12’...
+	...
+	[nix-shell:~/nixpkgs]$ which irb
+	/nix/store/945sd3dbynzpkqdd71cqqpsl8gwi9zsq-ruby-2.0.0-p647/bin/irb
+	
+	[nix-shell:~/nixpkgs]$ irb
+	irb(main):001:0> puts RUBY_VERSION
+	2.0.0
+	=> nil
+	irb(main):002:0>
+
+	nix@salo:~/nixpkgs$ nix-shell -p ruby_2_4
+	these paths will be fetched (3.13 MiB download, 15.30 MiB unpacked):
+	  /nix/store/wly748apb5r37byvvgq85hshgzcahv0y-ruby-2.4.0
+	fetching path ‘/nix/store/wly748apb5r37byvvgq85hshgzcahv0y-ruby-2.4.0’...
+	...
+	[nix-shell:~/nixpkgs]$ which irb
+	/nix/store/wly748apb5r37byvvgq85hshgzcahv0y-ruby-2.4.0/bin/irb
+	
+	[nix-shell:~/nixpkgs]$ irb
+	irb(main):001:0> puts RUBY_VERSION
+	2.4.0
+	=> nil
+	irb(main):002:0>
+
+We haven't even started to scratch the surface in this intro, there's lots
+of really exciting stuff I've not even mentioned, like how you can always
+rollback to the environment at an earlier state: every mutation to the
+environment is recorded, so every time you install or uninstall a nixpkg
+a new "generation" of the environment is created, and it's always possible to
+immediately rollback to some earlier generation. NixOS itself takes all these
+super exciting ideas and applies them to an entire operating system, where
+each user has their own environment, so ruby for one user might mean ruby2.0
+and ruby for another might mean ruby2.4. Hopefully it's clear now how these
+different versions of the same package can live in harmony under NixOS.
+
+I hope I've managed to convey some of nix's coolness in this short space,
+if I have then you should definitely check lethalman's "nix-pills"[1]
+series for a really deep explanation of how nix works internally and how
+to create nixpkgs from scratch. There's also ofcourse the NixOS website[2]
+and `#nixos` on `irc.freenode.net` which is probably one of the friendliest
+communities out there.
+
+[1]: http://lethalman.blogspot.co.uk/2014/07/nix-pill-1-why-you-should-give-it-try.html
+[2]: https://nixos.org/

Added a comment: start here page
diff --git a/suggestion-box/comment_4_a5f5482356eed8ff507397900a4085c6._comment b/suggestion-box/comment_4_a5f5482356eed8ff507397900a4085c6._comment
new file mode 100644
index 0000000..ea2d04c
--- /dev/null
+++ b/suggestion-box/comment_4_a5f5482356eed8ff507397900a4085c6._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="abhidg"
+ avatar="http://cdn.libravatar.org/avatar/5323e346ef1a67d6c2ee6ee9ac32b68d"
+ subject="start here page"
+ date="2017-07-14T11:39:04Z"
+ content="""
+Nice collection of articles! Might be helpful to have a \"start here\" page for people new to the site - also grouping things by technical level. For example the introduction to... series could be tagged somehow so people can just start off with the basics.
+"""]]

creating tag page tags/clock
diff --git a/tags/clock.mdwn b/tags/clock.mdwn
new file mode 100644
index 0000000..50f3f75
--- /dev/null
+++ b/tags/clock.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged clock"]]
+
+[[!inline pages="tagged(clock)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/time-clocks-what-are.mdwn b/posts/time-clocks-what-are.mdwn
new file mode 100644
index 0000000..b3902c3
--- /dev/null
+++ b/posts/time-clocks-what-are.mdwn
@@ -0,0 +1,140 @@
+[[!meta date="Wed, 12 Jul 2017 12:00:13 +0000"]]
+[[!meta title="Time - What are clocks?"]]
+[[!meta author="Richard Maw"]]
+[[!tag time clock]]
+
+## System calls
+
+You can't talk about time without clocks.
+A standard definition of clocks is "An instrument to measure time".
+
+Strictly speaking the analogy isn't perfect,
+since these clocks aren't just different ways of measuring time,
+they measure some different notions of time,
+but this is a somewhat philosophical point.
+
+The interface for this in Linux are system calls with a `clkid_t` parameter,
+though not all system calls are valid for every clock.
+
+*   [clock_adjtime(2)][]
+*   [clock_gettime(2)][]
+*   [clock_getres(2)][]
+*   [clock_settime(2)][]
+*   [clock_nanosleep(2)][]
+*   [timer_create(2)][]
+*   [timer_settime(2)][]
+*   [timer_gettime(2)][]
+*   [timer_getoverrun(2)][]
+*   [timer_delete(2)][]
+*   [timerfd_create(2)][]
+*   [timerfd_gettime(2)][]
+*   [timerfd_settime(2)][]
+
+This is not an exhaustive list of system calls,
+since there are also older system calls for compatibility with POSIX
+or other UNIX standards,
+that offer a subset of the functionality of the above ones.
+
+System calls beginning `clock_` are about getting the time or waiting,
+beginning `timer_` are for setting periodic or one-shot timers,
+`timerfd_` are for timers that can be put in event loops.
+
+For the sake of not introducing too many concepts at once,
+we're going to start with the simplest clock and work our way up.
+
+## `CLOCK_MONOTONIC_RAW`
+
+The first clock we care about is `CLOCK_MONOTONIC_RAW`.
+
+This is the simplest clock.
+
+It it initialised to an arbitrary value on boot
+and counts up at a rate of one second per second to the best of its ability.
+
+This clock is of limited use on its own
+since the only clock-related system calls that work with it are
+[clock_gettime(2)][] and [clock_getres(2)][].
+It can be used to determine the order of events,
+if the time of the event was recorded
+and the relative time difference between when they happened,
+since we know that the clock increments one second per second.
+
+## Example
+
+In this [[program below|time-clocks-what-are/zero-time.c]],
+we time how long it takes to read 4096 bytes from `/dev/zero`,
+and print the result.
+
+[[!format C """
+#include <stdio.h> /* fopen, fread, printf */
+#include <time.h> /* clock_gettime, CLOCK_MONOTONIC_RAW, struct timespec */
+
+int main(void) {
+    FILE *devzero;
+    int ret;
+    struct timespec start, end;
+    char buf[4096];
+
+    devzero = fopen("/dev/zero", "r");
+    if (!devzero) {
+        return 1;
+    }
+
+    /* get start time */
+    ret = clock_gettime(CLOCK_MONOTONIC_RAW, &start);
+    if (ret < 0) {
+        return 2;
+    }
+
+    if (fread(buf, sizeof *buf, sizeof buf, devzero) != sizeof buf) {
+        return 3;
+    }
+
+    /* get end time */
+    ret = clock_gettime(CLOCK_MONOTONIC_RAW, &end);
+    if (ret < 0) {
+        return 4;
+    }
+
+    end.tv_nsec -= start.tv_nsec;
+    if (end.tv_nsec < 0) {
+        end.tv_sec--;
+        end.tv_nsec += 1000000000l;
+    }
+    end.tv_sec -= start.tv_sec;
+
+    printf("Reading %zu bytes took %.0f.%09ld seconds\n",
+           sizeof buf, (double)end.tv_sec, (long)end.tv_nsec);
+
+    return 0;
+}
+"""]]
+
+---
+
+You're possibly curious about the naming of the clock called `MONOTONIC_RAW`.
+
+In the next article we will talk about `CLOCK_MONOTONIC`,
+which may help you understand why it's named the way it is.
+
+I suggested the uses of this clock are for the sequencing of events
+and for calculating the relative period between them.
+If you can think of another use please send us a comment.
+
+If you like to get hands-on, you may want to try
+reimplementing the above program in your preferred programming language,
+or extending it to time arbitrary events.
+
+[clock_adjtime(2)]: http://man7.org/linux/man-pages/man2/clock_adjtime.2.html
+[clock_gettime(2)]: http://man7.org/linux/man-pages/man2/clock_gettime.2.html
+[clock_getres(2)]: http://man7.org/linux/man-pages/man2/clock_gettime.2.html
+[clock_settime(2)]: http://man7.org/linux/man-pages/man2/clock_gettime.2.html
+[clock_nanosleep(2)]: http://man7.org/linux/man-pages/man2/clock_nanosleep.2.html
+[timer_create(2)]: http://man7.org/linux/man-pages/man2/timer_create.2.html
+[timer_settime(2)]: http://man7.org/linux/man-pages/man2/timer_settime.2.html
+[timer_gettime(2)]: http://man7.org/linux/man-pages/man2/timer_settime.2.html
+[timer_getoverrun(2)]: http://man7.org/linux/man-pages/man2/timer_getoverrun.2.html
+[timer_delete(2)]: http://man7.org/linux/man-pages/man2/timer_delete.2.html
+[timerfd_create(2)]: http://man7.org/linux/man-pages/man2/timerfd_create.2.html
+[timerfd_gettime(2)]: http://man7.org/linux/man-pages/man2/timerfd_gettime.2.html
+[timerfd_settime(2)]: http://man7.org/linux/man-pages/man2/timerfd_settime.2.html
diff --git a/posts/time-clocks-what-are/zero-time.c b/posts/time-clocks-what-are/zero-time.c
new file mode 100644
index 0000000..4fe766a
--- /dev/null
+++ b/posts/time-clocks-what-are/zero-time.c
@@ -0,0 +1,42 @@
+#include <stdio.h> /* fopen, fread, printf */
+#include <time.h> /* clock_gettime, CLOCK_MONOTONIC_RAW, struct timespec */
+
+int main(void) {
+    FILE *devzero;
+    int ret;
+    struct timespec start, end;
+    char buf[4096];
+
+    devzero = fopen("/dev/zero", "r");
+    if (!devzero) {
+        return 1;
+    }
+
+    /* get start time */
+    ret = clock_gettime(CLOCK_MONOTONIC_RAW, &start);
+    if (ret < 0) {
+        return 2;
+    }
+
+    if (fread(buf, sizeof *buf, sizeof buf, devzero) != sizeof buf) {
+        return 3;
+    }
+
+    /* get end time */
+    ret = clock_gettime(CLOCK_MONOTONIC_RAW, &end);
+    if (ret < 0) {
+        return 4;
+    }
+
+    end.tv_nsec -= start.tv_nsec;
+    if (end.tv_nsec < 0) {
+        end.tv_sec--;
+        end.tv_nsec += 1000000000l;
+    }
+    end.tv_sec -= start.tv_sec;
+
+    printf("Reading %zu bytes took %.0f.%09ld seconds\n",
+           sizeof buf, (double)end.tv_sec, (long)end.tv_nsec);
+
+    return 0;
+}

creating tag page tags/format
diff --git a/tags/format.mdwn b/tags/format.mdwn
new file mode 100644
index 0000000..106fbf1
--- /dev/null
+++ b/tags/format.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged format"]]
+
+[[!inline pages="tagged(format)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/data
diff --git a/tags/data.mdwn b/tags/data.mdwn
new file mode 100644
index 0000000..e0b1077
--- /dev/null
+++ b/tags/data.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged data"]]
+
+[[!inline pages="tagged(data)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/open
diff --git a/tags/open.mdwn b/tags/open.mdwn
new file mode 100644
index 0000000..5ae3901
--- /dev/null
+++ b/tags/open.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged open"]]
+
+[[!inline pages="tagged(open)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/open-data-formats.mdwn b/posts/open-data-formats.mdwn
new file mode 100644
index 0000000..a182653
--- /dev/null
+++ b/posts/open-data-formats.mdwn
@@ -0,0 +1,54 @@
+[[!meta date="Wed, 05 Jul 2017 12:00:06 +0000"]]
+[[!meta title="Open your minds, and your data (formats)"]]
+[[!meta author="Daniel Silverstone"]]
+[[!tag data format open]]
+
+Whether I am writing my own program, or chosing between existing solutions,
+one aspect of the decision making process which always weighs heavily on my
+mind is that of the input and output data formats.
+
+I have been spending a lot of my work days recently working on converting data
+from a proprietary tool's export format into another tool's input format.  This
+has involved a lot of [XML][] diving, a lot more swearing, and a non-trivial
+amount of pain.  This drove home to me once more that the format of input and
+output of data is such a critical part of software tooling that it must weigh
+as heavily as, or perhaps even more heavily than, the software's functionality.
+
+As [Tannenbaum][] tells us, the great thing about standards is that there's so
+many of them to choose from. [XKCD][] tells us, [how that comes about][tgtas].
+Data formats are many and varied, and suffer from specifications as vague as
+"plain text" to things as complex as the structure of data stored in custom
+database formats.
+
+If you find yourself writing software which requires a brand new data format
+then, while I might caution you to examine carefully if it really *does* need a
+new format, you should ensure that you document the format carefully and
+precisely.  Ideally give your format specification to a third party and get
+them to implement a reader and writer for your format, so that they can check
+that you've not missed anything.  Tests and normative implementations can help
+prop up such an endeavour admirably.
+
+Be sceptical of data formats which have "implementation specific" areas, or
+"vendor specific extension" space because this is where everyone will put the
+most important and useful data.  Do not put such beasts into your format
+design.  If you worry that you've made your design too limiting, deal with that
+*after* you have implemented your use-cases for the data format.  Don't be
+afraid to version the format and extend later; but always ensure that a given
+version of the data format is well understood; and document what it means to be
+presented with data in a format version you do not normally process.
+
+Phew.
+
+---
+
+Given all that, I exhort you to consider carefully how your projects manage
+their input and output data, and for these things to be uppermost when you are
+choosing between different solutions to a problem at hand.  Your homework is,
+as you may have grown to anticipate at this time, to look at your existing
+projects and check that their input and output data formats are well documented
+if appropriate.
+
+[XML]: https://en.wikipedia.org/wiki/XML
+[Tannenbaum]: http://www.goodreads.com/quotes/589703-the-good-thing-about-standards-is-that-there-are-so
+[XKCD]: https://xkcd.com/
+[tgtas]: https://xkcd.com/927/

creating tag page tags/time
diff --git a/tags/time.mdwn b/tags/time.mdwn
new file mode 100644
index 0000000..d15e9d5
--- /dev/null
+++ b/tags/time.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged time"]]
+
+[[!inline pages="tagged(time)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/time-what-is-time.mdwn b/posts/time-what-is-time.mdwn
new file mode 100644
index 0000000..9257939
--- /dev/null
+++ b/posts/time-what-is-time.mdwn
@@ -0,0 +1,57 @@
+[[!meta date="Wed, 28 Jun 2017 12:00:07 +0000"]]
+[[!meta title="What is Time?"]]
+[[!meta author="Richard Maw"]]
+[[!tag time]]
+
+Time is a big enough subject that I'd never finish writing about it.
+
+Fortunately this is a Linux technical blog,
+so I only have to talk about it from that perspective.
+
+In a departure from our usual article series format,
+we are going to start with an introductory article
+and follow up starting from basics,
+introducing new concepts in order of complexity.
+
+# What is time?
+
+Time is seconds since the [unix epoch][].
+
+The Unix epoch is midnight, Thursday, 1st January 1970 in the [UTC][] time zone.
+
+If you know the unix time and how many seconds in each day since then
+you can use the unix timestamp to work out what time it is now in UTC time.
+
+If you want to know the time in another timezone the naïve thing
+is to apply a timezone offset based on how far or behind the zone is
+compared to UTC.
+
+This is non-trivial since time is a political issue,
+requiring global coordination
+with hundreds of countries coming in and out of [daylight saving time][]
+and various other administrative changes,
+time often changes.
+
+Some times don't exist in some timezones.
+[Samoa skipped a day and changed time zone][samoa-tz].
+
+A side-effect of your system clock being in Unix time
+is that to know local time you need to know where you are.
+
+The talk linked to in
+<https://fosdem.org/2017/schedule/event/python_datetime/>
+is primarily about time in python,
+but covers the relationship between time stamps,
+clock time and time zones.
+
+<http://www.creativedeletion.com/2015/01/28/falsehoods-programmers-date-time-zones.html>
+is a good summary of some of the common misconceptions of time zone handling.
+
+---
+
+Now that we've covered some of the concepts
+we can discuss in future articles how this is implemented in Linux.
+
+[unix epoch]: https://en.wikipedia.org/wiki/Unix_time
+[UTC]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
+[samoa-tz]: http://www.nytimes.com/2011/12/30/world/asia/samoa-to-skip-friday-and-switch-time-zones.html

creating tag page tags/diary
diff --git a/tags/diary.mdwn b/tags/diary.mdwn
new file mode 100644
index 0000000..ea5cfee
--- /dev/null
+++ b/tags/diary.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged diary"]]
+
+[[!inline pages="tagged(diary)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/journalling.mdwn b/posts/journalling.mdwn
new file mode 100644
index 0000000..2ce65f6
--- /dev/null
+++ b/posts/journalling.mdwn
@@ -0,0 +1,87 @@
+[[!meta date="Wed, 21 Jun 2017 12:00:08 +0000"]]
+[[!meta title="On the usefulness of a personal journal"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag journal diary]]
+
+A lot of people keep a diary. This is a time-tested way of ensuring
+future historians have juicy rumours to read and write books about.
+A journal is like a diary, but it's meant to be more serious and less
+saucy.
+
+I've been keeping a journal for some years now. It's been good in
+several ways:
+
+* It's a private place where I can vent entirely without any
+  inhibition. As long as I don't leak the content, I can write
+  anything there, things I couldn't share even with my closest friends
+  and loved ones. In my journal I don't need to be fair or balanced or
+  diplomatic; if calling my boss a poophead helps me, I can do
+  that in my journal. More importantly, apart from name-calling, I can
+  be open in my journal about my hopes and dreams, and speculate as
+  freely as I need to about all sorts of crazy ideas. If I want to
+  fantasize about writing my own Debian installer, my journal is where
+  I'll do it. In my journal I don't have to worry about people
+  misunderstanding me, or attacking any vague, half-developed crazy
+  ideas, and ridicule me about them for the next several years.
+
+  My journal is a safe place. (This is one of the reasons why my
+  [backups are encrypted][].)
+
+* It's a place to keep an external memory. One of the the things I put
+  in my journal is a stream of consciousness while developing. This
+  allows me to answer questions of the form "what the bleeding heck
+  was I thinking then designing this software" with quotes from my
+  younger self. Perhaps more usefully, this can be applied to
+  debugging as well: tricky problems often involve a lot of data to be
+  kept to fully understand what's going on, and a written journal is a
+  better place for that than the brain.
+  
+  A bug tracker is usually not a good place for this, or not the full
+  stream of consciousness. Most of that stream is necessary for the
+  process, but other people shouldn't be flooded with all of it, only
+  the actually relevant parts.
+
+* I also put all sorts of other bits of information into my journal.
+  In fact, over the years it has developed into a
+  [personal knowledge base][], where I can find a bunch of things that
+  are relevant to me, but not necessarily easy to find online. As an
+  example, what's the command to do [TOTP][] on Linux that works with
+  Amazon? (`oathtool --base32 --totp`, not too difficult to find but
+  easier in my journal.)
+
+  Some information is private in nature, such as who were the people I
+  had that interesting lunch with at that conference that one time.
+
+[backups are encrypted]: http://obnam.org/encryption/
+[personal knowledge base]: https://en.wikipedia.org/wiki/Personal_knowledge_base
+[TOTP]: https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm
+
+There are a myriad of tools for keeping a journal, or personal
+knowledge base. There's wikis of various flavors, plain text files in
+git, online document services, etc etc. You can keep it on paper as
+well, though that makes grepping harder. As I prefer to not pour my
+heart and soul into a service run by other people, my journal is an
+[ikiwiki][] instance that I run on my laptop, which renders a static
+HTML that is served via Apache on my laptop (and only to my laptop).
+This satisfies my needs for ease of use and privacy.
+
+Using a wiki engine for this is nice, because linking adds a lot of
+power and can make finding relevant information faster. Using the
+ikiwiki `inline` directive, which produces pages by collecting other
+pages based on a pattern, I get pages for particular people (link to
+the person, the person's page includes the page linking to them),
+topics (e.g., projects), tags, and more. Quite nifty, and I'm afraid I
+can't show you.
+
+[ikiwiki]: http://ikiwiki.info/
+
+Keeping a journal takes a bit of effort, of course. It also takes time
+for a journal to become useful: having diary entries for a week
+probably doesn't help much. Having them from a decade changes this in
+a qualitative, not just a quantitative way. Do you remember what you
+got your loved as a present seven years ago? I don't even remember
+what I got as a present last year.
+
+Give it a try. It doesn't have to be perfect, but you need to keep
+doing it. Report back in a comment below in four years from now and
+tell use if it was helpful to you.

creating tag page tags/yakshaving
diff --git a/tags/yakshaving.mdwn b/tags/yakshaving.mdwn
new file mode 100644
index 0000000..17450d5
--- /dev/null
+++ b/tags/yakshaving.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged yakshaving"]]
+
+[[!inline pages="tagged(yakshaving)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/development
diff --git a/tags/development.mdwn b/tags/development.mdwn
new file mode 100644
index 0000000..94f1630
--- /dev/null
+++ b/tags/development.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged development"]]
+
+[[!inline pages="tagged(development)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/the-way-of-the-yak.mdwn b/posts/the-way-of-the-yak.mdwn
new file mode 100644
index 0000000..d113645
--- /dev/null
+++ b/posts/the-way-of-the-yak.mdwn
@@ -0,0 +1,51 @@
+[[!meta date="Wed, 14 Jun 2017 12:00:07 +0000"]]
+[[!meta title="Piecemeal development"]]
+[[!meta author="Richard Maw"]]
+[[!tag development yakshaving]]
+
+Daniel recently discussed the [Minimum Viable Product][] development approach.
+
+As discussed in his article it has the disadvantage
+that it results in a lot of code that will be thrown away
+after being deemed to be insufficient.
+
+An alternative approach is to do some analysis up-front
+and determine the full set of functionality
+and split the work into sub-projects,
+so that each component is a project of value by itself.
+
+For example, you may be writing a daemon in python
+which needs to be able to safely create and read PID files.
+
+You would then need to investigate which projects exist for doing so,
+evaluate whether they are sufficient,
+and if not either develop a replacement or contribute to an existing project.
+
+For an ambitious project this can provide more good in the short term,
+since while it will take a while before the project's main goal is achieved,
+some of the component parts are already of value.
+
+This can be better for motivation than the [Minimum Viable Product][] approach
+if the developers involved tend towards obsessing over minutiae
+and having the "correct" solution for every little part of the project.
+
+However it is particularly vulnerable to losing motivation
+from introspection of the current state of the project compared to its goal,
+since it takes longer to get to something demonstrable
+if feedback on the individual components is not readily available.
+
+This may be viewed as an [agile][] vs. [waterfall][] development methodology,
+since it requires a large amount of analysis up-front
+to determine which components are required
+and which should be split out into separate projects,
+but those individual components may be reusable.
+
+Similarly, if it turns out that the goal of the project was bad,
+then at least the component parts of the project are salvageable.
+
+If the project does eventually fail,
+then at least lessons will have been learned for future attempts.
+
+[Minimum Viable Product]: https://en.wikipedia.org/wiki/Minimum_viable_product
+[agile]: https://en.wikipedia.org/wiki/Agile_software_development
+[waterfall]: https://en.wikipedia.org/wiki/Waterfall_model

publishing
diff --git a/posts/mvp.mdwn b/posts/mvp.mdwn
new file mode 100644
index 0000000..15732df
--- /dev/null
+++ b/posts/mvp.mdwn
@@ -0,0 +1,56 @@
+[[!meta date="Wed, 07 Jun 2017 12:00:06 +0000"]]
+[[!meta title="Minimal Viable Project"]]
+[[!meta author="Daniel Silverstone"]]
+
+Quite a while ago now, Lars spoke about writing the
+[scaffolding](/posts/scaffolding) of your projects as a first step.  We've
+covered all sorts of things like how to
+[lay out](/posts/source-tree-organisation) your codebase and recently about
+[motivation](/posts/motivation) for projects in the first place.
+
+And all this is good.  You've decided you want to write something awesome, you
+have a design which you think will lead to an amazing program which will wow
+the world.  But it's going to take you about six months of engineering before
+you can get to the result you've designed for.  That's an awfully long time
+before you know if you're doing the right thing.
+
+Lars spoke of TDD (test driven development) in his scaffolding article and
+that's an excellent way of ensuring that everything you write is validated.
+Sadly it does nothing to guarantee that everything you write is useful or
+desirable in implementing your final solution.  There are a number of ways of
+bridging this gap and today I'm going to talk about one of them.
+
+The
+"[Minimal Viable Product](https://en.wikipedia.org/wiki/Minimum_viable_product)"
+is a process whereby you develop the least you possibly can to give yourself an
+edge or unique selling point; and the same thing can be applied to software
+engineering.  You can shorten the feedback loop, reduce the chance of
+developing something undesirable, and get to a program which is of use to you
+as soon as possible; if you focus your early development effort on a minimal
+viable project.
+
+You should take time, after you've done your high level architecture and design
+discussions to [gather by a whiteboard](/posts/whiteboarding) and come up with
+the absolute bare minimum of your feature set which you could implement and
+produce something which can actually be used for a real-world use-case.
+
+Then, after you've implemented your MVP you've likely had to amend your design
+documentation a good amount (possibly even fundamentally).  Fortunately for
+you, you come out of the process with something which does something useful
+(and thus can be effectively evaluated) and every change you make to your
+design as a result has a grounding in the reality of implementation.
+
+Your MVP could be thought of as a prototype.  Indeed some developers prefer, at
+this point, to throw away the MVP and reimplement it again with the insights
+gained during the implementaiton.  What is important about an MVP though, is
+that once you've been around the prototype loop a few times, you *keep* the MVP
+code and evolve your final project out of that codebase.  This critical
+difference between an MVP and a pure prototype allows you to bring online
+continuous testing and continuous integration and deployment if appropriate,
+the moment you have your MVP ready (or even before).  And remember, 
+[if it's not tested, it doesn't work](/posts/truism-4-if-it-is-not-tested).
+
+Your homework this week is to look at some of the designs or READMEs you've
+written of late, and think about what an MVP might be which could lead you to
+greater insights into the problem, or even toward your final solution.
+

publishing
diff --git a/posts/complexity-in-systemd.mdwn b/posts/complexity-in-systemd.mdwn
new file mode 100644
index 0000000..55f657a
--- /dev/null
+++ b/posts/complexity-in-systemd.mdwn
@@ -0,0 +1,184 @@
+[[!meta date="Wed, 31 May 2017 12:00:05 +0000"]]
+[[!meta title="Complications arising from having a complex init"]]
+[[!meta author="Richard Maw"]]
+[[!tag process daemon cgroup systemd init]]
+
+Useful, secure, finished. Pick two.
+
+I've just spent a long time writing
+about how [systemd][] is the solution
+to all your process management reliability woes.
+
+As with everything though,
+as I've alluded to in the subtitle,
+there are trade-offs.
+
+What's the catch?
+-----------------
+
+It is arguable that increasing the responsibilities for [init][],
+historically a very simple daemon,
+is a dangerous thing to do.
+
+I believe these changes have been warranted,
+since the traditional UNIX process model
+assumes processes are well-written and benign.
+
+### Security updates
+
+To accommodate the changing world,
+[init][] is now sufficiently complicated that it requires security updates.
+
+This is a problem because you can only have one [init][] process,
+so you can't just kill the old version and start a new one.
+
+[systemd][] has to work around this by re-executing `/sbin/init`
+when it, or any of its dependent libraries, have been updated.
+
+This mechanism should not be relied upon,
+since it can fail and if it does fail recovery requires a reboot,
+so if you need to be prepared to reboot on update,
+why not just reboot the system when an update is required?
+
+### Rebooting woes
+
+Rebooting is also further complicated by [init][] being extended.
+
+If a library that a process depends on is removed as part of an update
+then the running process may keep a copy of it open
+until the process re-executes or terminates.
+
+This means file systems will refuse to be remounted as read-only
+until the process stops using certain files.
+This is hugely problematic if the filesystem is the root file system
+and the process is init,
+since init will want to remount the file system before terminating
+and the file system will want init to terminate before remounting.
+
+Previously the approach would be to shut-down
+without remounting the file system read-only,
+but this doesn't cleanly unmount the file system
+so was a source of file system corruption.
+
+The solution to this employed by [systemd][]
+is for the init process to execute a [systemd-shutdown][] binary.
+
+So why not move the complicated bits out of PID 1?
+--------------------------------------------------
+
+PID 1 is complex, and this is a problem.
+Therefore either [systemd][]'s developers don't consider the problems important
+or there are good reasons why it can't be otherwise.
+
+So, what responsibilities does PID 1 have,
+and why do they have to be in PID 1?
+
+### Process reaping
+
+When a process terminates before reaping its child subprocesses,
+all those subprocesses are adopted by PID 1,
+which is then responsible for reaping them.
+
+`PR_SET_CHILD_SUBREAPER` was added to [prctl(2)][]
+which allows a different process subreaper in the process hierarchy,
+so that gets to reap orphaned subprocesses instead of PID 1.
+
+However PID 1 still neads to be able to reap subreapers,
+so PID 1 needs the same reaping logic,
+and both implementations need to be either shared or maintained,
+at which point it's less difficult to just rely on PID 1 doing it.
+
+Traditional init systems perform this function,
+so it is not controversial for [systemd][] to perform this.
+
+### Spawning processes
+
+There are no special requirements necessary to spawn subprocesses,
+so a separate process could be started to spawn subprocesses.
+
+Unfortunately this has the same bootstrapping problem,
+where PID 1 needs the same logic for starting its helpers
+as needs to be used for arbitrary code in the rest of the system.
+
+Traditional init systems perform this function,
+so it is not controversial for [systemd][] to perform this.
+
+### Managing cgroups
+
+Because processes can't be trusted to not escape,
+[cgroups][] are required to contain them.
+
+A single process is required to manage them.
+
+If services started by init are to be contained by cgroups,
+then the cgroup management service
+must either be the init process
+or must be started by the init process
+and have special logic to contain itself first.
+
+This is tractable, but if it's a separate process,
+then some form of IPC is required,
+which adds extra latency, complexity and points of failure.
+
+A similar concern exists in the form of [journald][],
+which is a separate service that [systemd][] needs to communicate with
+to get it to log the output of new services to a file.
+
+This complexity already causes [systemd][] trouble,
+as a crashing [journald][] can bring the whole system to a halt,
+so similar complications should be avoided.
+
+### Communicating via [DBus][]
+
+The init process needs some form of IPC to instruct it to do things.
+
+Historically this was just `telinit`
+writing to the `/dev/initctl` FIFO,
+so was a pretty trivial form of IPC.
+
+However we've established that init now requires new responsibilities,
+so requires a much richer form of IPC.
+
+Rather than inventing some bespoke IPC mechanism,
+[systemd][] uses [DBus][].
+
+[systemd][] also participates in the system bus,
+once the [DBus][] daemon has been started,
+which adds extra complexity since the [DBus][] daemon is started by [systemd][].
+
+This is handled by [systemd][] also handling point-to-point [DBus][],
+though attempts have been made to move [DBus][] into the kernel
+in the form of [AF_BUS][], [kdbus][] and most recently [bus1][],
+and there has also been discussion
+of whether [systemd][] should be a [DBus][] daemon
+to break this circular dependency.
+
+Summary
+=======
+
+The traditional UNIX process model wasn't designed to support a complex init,
+because it assumed that programs would be benign and well written.
+
+Because you can't trust processes to clean up after themselves properly
+you need to make init more complicated to cope with it.
+
+Because init is complicated it needs to be able to be updated.
+
+Because the UNIX process model doesn't have a way to safely replace init
+you have to allow for it failing and needing a reboot,
+so you can't safely perform live updates.
+
+Alternative ways of structuring init would make it even more complex
+so more opportunity for things to go wrong.
+
+[init]: https://en.wikipedia.org/wiki/Init
+[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
+[wait(2)]: http://man7.org/linux/man-pages/man2/waitpid.2.html
+[systemd-shutdown]: https://www.freedesktop.org/software/systemd/man/systemd-halt.service.html
+[prctl(2)]: http://man7.org/linux/man-pages/man2/prctl.2.html
+[cgroups]: https://en.wikipedia.org/wiki/Cgroups
+[journald]: https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html
+[DBus]: https://www.freedesktop.org/wiki/Software/dbus/
+[AF_BUS]: https://lwn.net/Articles/504970/
+[kdbus]: https://www.freedesktop.org/wiki/Software/systemd/kdbus/
+[bus1]: http://www.bus1.org/

publishing
diff --git a/posts/hwadc.mdwn b/posts/hwadc.mdwn
new file mode 100644
index 0000000..82eab98
--- /dev/null
+++ b/posts/hwadc.mdwn
@@ -0,0 +1,105 @@
+[[!meta date="Wed, 24 May 2017 12:00:06 +0000"]]
+[[!meta title="A WadC successor in Haskell?"]]
+[[!meta author="Jon Dowland"]]
+
+> Today's posting is by a guest author, [Jon Dowland](https://jmtd.net/).
+
+---
+
+I wanted to refresh my Haskell skills recently so I picked up an old idea I'd
+had of writing a successor to [WadC](https://jmtd.net/wadc/) in Haskell. WadC
+is a LOGO-like language for making 2D drawings (Doom maps). You write a
+sequence of instructions that move a "pen" around and draw lines, place things,
+etc. It looks a bit like this:
+
+    ...
+    movestep(32,32)
+    thing
+    straight(256)
+    rotright
+    straight(512)
+    rotright
+    ...
+
+The driving force behind for writing a successor to WadC is to work around one of its most
+serious limitations: you do not have direct access to the data structure that
+you are building. Once you place a line, it's defined and you can't change it,
+or even query existing drawn lines to find out if it exists. The appeal of using
+Haskell would be to give you access to the data structure that's "behind the
+scenes" as well as Haskell's rich features and libraries.
+
+WadC's syntax, like LOGO, resembles an ordered sequence of operations that
+manipulate some hidden state relating to the Pen: its orientation, whether its
+on the "paper" or not, what colour line is being drawn, etc. I thought this
+would look particularly nice in Haskell's "do notation" syntax, e.g.:
+
+    blah = do
+        down
+        straight 64
+        rotright
+        straight 128
+        rotright
+    ...
+
+Ignoring the syntax issue for a minute and thinking just about types, the most
+natural type to me for the atomic operations would be something like `Context ->
+Context`: simply put, each function would receive the current state of the world,
+and return a new state. For example `Context` could be something like
+
+    data Context = Context { location :: Point          -- (x,y)
+                           , orientation :: Orientation -- N/E/S/W
+                           , linedefs :: [Line]         -- Line = from/to (x,y)/(x,y)
+                           , penstate :: PenState       -- up or down
+                           ...
+
+An example of a simple low-level function that would work with this:
+
+        down c = c { penstate = Down }
+
+The immediate advantage here over WadC is that the functions have access to all
+of the existing context: they could not only append lines, say, but replace any
+existing lines too. I was envisaging that you might, for example, adjust
+all drawn lines as if you were using a completely different geometric model to
+get some weird effects (such as one axis being warped towards a single point).
+Or perhaps you would super-impose two separate drawings and have fine control
+over how overlapping regions have their properties combined (one overrides the
+other, or blend them, etc.)
+
+The problem is in uniting the simple types with using do-notation, which
+requires the routines to be "wrapped up" in Monads. I got a prototype working
+by writing a custom Monad, but it required me to either modify the type of each
+of the low-level functions, or wrap each invocation of them inside the
+do-block. If you imagine the wrap function is called `wadL`, that means either
+
+    down = wadL down' where
+        down' c = c { penstate = Down }
+
+or
+
+    blah = do
+        wadL $ down
+        wadL $ straight 64
+        wadL $ rotright
+
+Both approaches are pretty ugly. The former gets ugly fast when the functions
+concerned are more complicated in the first place; the latter pretty much
+throws away the niceness of using do-notation at all.
+
+An alternative solution is one that the
+[Diagrams](http://projects.haskell.org/diagrams/) package uses: define a new
+infix operator which is just function composition (`.`) backwards:
+
+    down        &
+    straight 64 &
+    rotright
+
+(*Diagrams* uses `#` but I prefer `&`)
+
+By playing around with this I've achieved my original goal of refreshing my
+Haskell skills. Unfortunately I don't have the time or inclination to continue
+with this side-project right now so I haven't published a working
+Haskell-powered Doom map editor.
+
+If I return to this again, I might explore writing a completely distinct
+language (like WadC is) with the compiler/interpreter likely written using
+Haskell.

Added a comment: > I hope that you'll take this on board
diff --git a/posts/whiteboarding/comment_1_efdc4699dc2338d37a551116c2adcd9d._comment b/posts/whiteboarding/comment_1_efdc4699dc2338d37a551116c2adcd9d._comment
new file mode 100644
index 0000000..de30d92
--- /dev/null
+++ b/posts/whiteboarding/comment_1_efdc4699dc2338d37a551116c2adcd9d._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawl9FJMsOeSRP60lPMFDcb6WBhh-IVPr0gs"
+ nickname="Pete"
+ avatar="http://cdn.libravatar.org/avatar/ec40ad4baae25694ce8449714854a8a38be15e92d74be4db2d136331ced93b0b"
+ subject="> I hope that you'll take this on board "
+ date="2017-05-19T07:31:04Z"
+ content="""
+Lose three house points for that pun :)
+"""]]

publishing
diff --git a/posts/whiteboarding.mdwn b/posts/whiteboarding.mdwn
new file mode 100644
index 0000000..07889ca
--- /dev/null
+++ b/posts/whiteboarding.mdwn
@@ -0,0 +1,53 @@
+[[!meta date="Wed, 17 May 2017 12:00:06 +0000"]]
+[[!meta title="Whiteboarding your project"]]
+[[!meta author="Daniel Silverstone"]]
+
+Recently I spent time with our very own Lars Wirzenius, in Helsinki.  While
+there, I had the distinct pleasure of standing in front of a whiteboard with
+Lars and hashing out aspects of two different Free Software projects which we
+are both involved with.  We have talked about [irc](/posts/irc) in the past and
+we've talked about [being gracious](/posts/be-gracious) when dealing with your
+community.  In general we've only really spoken online interactions with your
+project (excepting when we spoke of [conferences](/posts/conferences)) but
+today I'd like to introduce you to the inestimable value of whiteboarding with
+your collaborators.
+
+While the value of having written discussion is very high, a log of what was
+said by whom and in response to what is very helpful, and nicely written design
+documentation can be critical to a project's success; the incredible bandwidth
+of face-to-face discussions is hard to beat.  Conferences are, as previously
+discussed, one of the ways to achieve this.  But for the raw base design work
+for a project, whiteboarding on your feet (or your rear-end I suppose) is one
+of the best ways I find to get the ideas flowing.
+
+Whiteboarding is best done in a small group.  Ideally two to four people.  You
+need to have a room to yourselves because you will be making a lot of noise;
+talking over each other as the ideas pop up; and generally making a lot of mess
+on the whiteboard.  If you can have multiple whiteboards in one room then
+larger projects can be easier to deal with.  I have successfully whiteboarded
+with a fold-up whiteboard on a café table, though that was a lot of work.
+
+The second thing that you really must have for whiteboarding is a camera.  You
+might get lucky and have a "smart" whiteboard which you can extract an image
+from, though I generally find those to be less effective than a quick snap from
+a camera phone before wiping the whiteboard down.
+
+Don't be afraid to write stuff up on the board which you're going to
+immediately say is wrong, because seeing it written up can spark ideas in
+others.  Whiteboards give you the ability to sketch out diagrams as well as
+APIs with equal ease - I find that sometimes the best way to work out how a
+state machine works is to draw it up, despite the fact that I am almost
+entirely incapable of thinking in images at all.
+
+Once you've done your design work and come to agreements, ensure that
+photographs of your whiteboards are circulated among the attendees.  At this
+point the most important step of all happens -- you *all* should write up what
+was discussed and the decisions which were arrived at.  Then you can all review
+each others' memories of what happened and come to a consensus as to the final
+decisions as a group.  Interpreting the whiteboards after the fact gives the
+attendees further chance to jog an idea which may have been fermenting in their
+minds since the session.
+
+I hope that you'll take this on board and try out whiteboarding with one of
+your projects just as soon as you can.  However, since it can be hard to just
+magic up a whiteboard, I won't set you homework this week.  Enjoy your respite.

creating tag page tags/init
diff --git a/tags/init.mdwn b/tags/init.mdwn
new file mode 100644
index 0000000..e4895fe
--- /dev/null
+++ b/tags/init.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged init"]]
+
+[[!inline pages="tagged(init)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/ptrace
diff --git a/tags/ptrace.mdwn b/tags/ptrace.mdwn
new file mode 100644
index 0000000..98ec702
--- /dev/null
+++ b/tags/ptrace.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged ptrace"]]
+
+[[!inline pages="tagged(ptrace)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/cgroup
diff --git a/tags/cgroup.mdwn b/tags/cgroup.mdwn
new file mode 100644
index 0000000..af14b3a
--- /dev/null
+++ b/tags/cgroup.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged cgroup"]]
+
+[[!inline pages="tagged(cgroup)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/upstart
diff --git a/tags/upstart.mdwn b/tags/upstart.mdwn
new file mode 100644
index 0000000..ea8a145
--- /dev/null
+++ b/tags/upstart.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged upstart"]]
+
+[[!inline pages="tagged(upstart)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/procrun-4-linux.mdwn b/posts/procrun-4-linux.mdwn
new file mode 100644
index 0000000..7c77c98
--- /dev/null
+++ b/posts/procrun-4-linux.mdwn
@@ -0,0 +1,112 @@
+[[!meta date="Wed, 10 May 2017 12:00:06 +0000"]]
+[[!meta title="Is your process running 4 - Linux-specific approaches"]]
+[[!meta author="Richard Maw"]]
+[[!tag process daemon cgroup systemd upstart init ptrace]]
+
+We previously discussed the traditional UNIX mechanisms for service management,
+and how they assumed benign and well written software.
+
+Fortunately Linux provides more than just traditional UNIX system calls,
+so offers some features that can be used to track processes more completely.
+
+Intercepting processes with [ptrace(2)][]
+===
+
+If you could run some code when a process creates a subprocess or exits
+then you could use this to track which processes are active
+and where they came from.
+
+Debuggers like [gdb(1)][] also need to know this information
+since you might want to set a breakpoint for subprocesses too.
+
+So it would be possible to do this using the same mechanism as debuggers.
+
+This is what [Upstart][] does to work out which process to track
+for double-forking daemons.
+
+Unfortunately a process cannot be traced by multiple processes,
+so if [Upstart][] is tracing a process to track its subprocesses
+then a debugger cannot be attached to the process.
+
+For [Upstart][] it detaches the debugger after it has worked out the main PID,
+so it's a small window where it is undebuggable,
+so it's only a problem for debugging faults during startup,
+but detaching after the double-fork means
+it can't trace any further subprocesses.
+
+Continuing to trace subprocesses adds a noticeable performance impact though,
+so it's for the best that it stops tracing after the double-fork.
+
+Store process in a [cgroup][cgroups]
+===
+
+[cgroups][] are a Linux [virtual filesystem][]
+that lets you create hierarchies to organise processes,
+and apply resource controls at each level.
+
+[cgroups][] were created to handle the deficiency
+of traditional UNIX resource control system calls
+such as [setrlimit(2)][],
+which only apply to a single process
+and can be thwarted by creating subprocesses,
+since while a process inherits limits of its parent process
+it does not share them with it.
+
+Subprocesses of a process in a [cgroup][cgroups] on the other hand
+are part of the same [cgroup][cgroups] and share the same resource limits.
+
+In each [cgroup][cgroups] directory there is a `cgroup.procs` virtual file,
+which lists the process IDs of every process in the [cgroup][cgroups],
+making it effectively a kernel-maintained PIDfile.
+
+This is what [systemd][] uses for its services,
+and you can request a [cgroup][cgroups] for your own processes
+by asking [systemd][] (via [systemd-run(1)][] or the DBus interface)
+or [cgmanager][] (via [cgm(1)][] or the DBus interface)
+to do so on your behalf.
+
+Why can't I mount my own cgroupfs?
+----------------------------------
+
+Unfortunately you can only safely have 1 process using a cgroup tree at a time,
+and you can only have one cgroupfs mounted at a time,
+so you always need to ask some daemon to manage cgroups on your behalf.
+
+See [Changes coming for systemd and control groups][]
+for why a single writer and a single hierarchy are required.
+
+Conclusion
+==========
+
+It is necessary to track all the subprocesses of a service somehow,
+using [ptrace(2)][] prevents it being used for debugging,
+[cgroups][] are an interface designed for this purpose
+but technical limitations mean you need to ask another service to do it.
+
+So I would recommend writing a [systemd service][systemd.service]
+if your processes are a per-system or per-user service,
+or to use the [DBus API][systemd-dbus-api] to create [cgroups][] if not.
+
+Thus [cgroups][] allow us to know our processes are running,
+and currently the best way to use cgroups is via [systemd][].
+The implications of relying on [systemd][] to do this
+are best served as a subject of another article.
+
+If you are interested in learning more about [cgroups][],
+I recommend reading [Neil Brown's excellent series on LWN
+](https://lwn.net/Articles/604609/).
+
+[gdb(1)]: http://man7.org/linux/man-pages/man1/gdb.1.html
+[ptrace(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
+[upstart]: http://upstart.ubuntu.com/
+[cgroups]: http://man7.org/linux/man-pages/man7/cgroups.7.html
+[virtual filesystem]: https://en.wikipedia.org/wiki/Virtual_file_system
+[setrlimit(2)]: http://man7.org/linux/man-pages/man2/setrlimit.2.html
+[init]: https://en.wikipedia.org/wiki/Init
+[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
+[cgmanager]: https://linuxcontainers.org/cgmanager/introduction/
+[systemd-run(1)]: http://man7.org/linux/man-pages/man1/systemd-run.1.html
+[cgm(1)]: http://manpages.ubuntu.com/manpages/yakkety/man1/cgm.1.html
+[systemd.service]: https://www.freedesktop.org/software/systemd/man/systemd.service.html
+[systemd-dbus-api]: https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/#theapis
+[Changes coming for systemd and control groups]: https://lwn.net/Articles/555920

publishing
diff --git a/posts/all-work-and-no-play.mdwn b/posts/all-work-and-no-play.mdwn
new file mode 100644
index 0000000..5bec864
--- /dev/null
+++ b/posts/all-work-and-no-play.mdwn
@@ -0,0 +1,74 @@
+[[!meta date="Wed, 03 May 2017 12:00:06 +0000"]]
+[[!meta title="All work and no play makes Daniel a dull boy…"]]
+[[!meta author="Daniel Silverstone"]]
+
+…or how to take a bad analogy far too far; without any goal in sight.
+
+Sometimes you just need a break from all the bits and bytes; all the integers
+and floats and strings.  Sometimes you just want to step away from the keyboard
+and do something completely different, such as bake a cake.  There's nothing so
+different from writing software as baking a cake, right?
+
+Right?
+
+…
+
+Wrong!
+
+When you cook anything, you're essentially executing a program.  If you're the
+sort of person who follows the recipe slavishly then you're executing a defined
+algorithm for turning ingredients into something else; if you're the sort of
+person who thinks recipes are essentially a guideline, then you're still
+running a program in your head, but it's more of a heuristic than an algorithm.
+
+In the process of running this program, you use tools, process inputs, and
+produce outputs.  You even likely have (albeit small, simplistic, and likely
+poorly defined) a test suite to ensure that you produce the right outputs (that
+of simply tasting things).
+
+What's even worse (assuming you were trying to get away from producing software
+rather than simply wanting dinner) as you go, even if you weren't expecting to,
+you likely are debugging and bugfixing your program as you learn more about how
+you want to transform inputs to outputs effectively and efficiently.
+
+> Okay, so if programming and cooking are just more of the same, then why this
+> article at all?
+
+In brief, everyone needs something to do when the code just doesn't flow.  I
+sometimes switch to reading a book, watching videos online, or going for a
+walk; but sometimes cooking is exactly the right thing to do.  At least a few
+other programmers must agree since there's any number of programmer oriented
+cooking-related tools out there, a yaml syntax or three for defining recipes,
+and some desktop environments which shall remain unnamed even consider recipe
+tools to be worth mentioning in their release notes :-)
+
+All this applies to those of us who slavishly try and write articles for you to
+enjoy every week.  As such, sometimes we just need to have fun.  Thus, your
+homework this week, assuming you're not allergic to any of the following, is
+to:
+
+1. Take two eggs and weigh them (shell on)
+2. Sift the same mass of self-raising flour and set aside.
+3. Melt the same mass of butter and beat the eggs (shell off), butter, and the
+   same mass of sugar together.
+4. Gently fold the flour into the wet mix, trying to not knock the air back
+   out of it.  (Or just use an electric whisk to keep it floofy)
+5. Divide the mix between two pre-greased and floured cake tins, and bake in
+   the centre of a pre-heated oven at (approximately) 170°C for 20-25 minutes
+   (check the centre with a skewer)
+6. Allow the cakes to stand for 10 minutes before turning out onto a wire rack
+   to cool thoroughly.
+7. Beat 150g to 250g of butter until smooth and soft (I prefer slightly salted
+   butter, but unsalted is fine too)
+8. Mix icing sugar into the butter, a spoonful at a time, beating it until
+   smooth each time.  Repeat until the icing tastes sweet rather than savoury.
+9. Spread a small bit of icing on the centre of a plate, and use that to stick
+   one of your sponges down.  Ice the top of the sponge and then pop the second
+   layer on top.  If you have enough icing left, smear it all over the cake,
+   remembering that presentation is far less important than deliciousness.
+
+Now serve slices of your delicious cake with cups of delicious tea or coffee.
+
+Also, please do share your favourite recipes in the comments below, before you
+take your coffee and cake and get on with coding up your latest masterpiece.
+

creating tag page tags/utmp
diff --git a/tags/utmp.mdwn b/tags/utmp.mdwn
new file mode 100644
index 0000000..d36612b
--- /dev/null
+++ b/tags/utmp.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged utmp"]]
+
+[[!inline pages="tagged(utmp)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/setsid
diff --git a/tags/setsid.mdwn b/tags/setsid.mdwn
new file mode 100644
index 0000000..c4d890b
--- /dev/null
+++ b/tags/setsid.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged setsid"]]
+
+[[!inline pages="tagged(setsid)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/pgroup
diff --git a/tags/pgroup.mdwn b/tags/pgroup.mdwn
new file mode 100644
index 0000000..de0fcfe
--- /dev/null
+++ b/tags/pgroup.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged pgroup"]]
+
+[[!inline pages="tagged(pgroup)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/wtmp
diff --git a/tags/wtmp.mdwn b/tags/wtmp.mdwn
new file mode 100644
index 0000000..4c5a977
--- /dev/null
+++ b/tags/wtmp.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged wtmp"]]
+
+[[!inline pages="tagged(wtmp)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/job
diff --git a/tags/job.mdwn b/tags/job.mdwn
new file mode 100644
index 0000000..69c8fb3
--- /dev/null
+++ b/tags/job.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged job"]]
+
+[[!inline pages="tagged(job)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/procrun-3-unix-sessions.mdwn b/posts/procrun-3-unix-sessions.mdwn
new file mode 100644
index 0000000..3c68360
--- /dev/null
+++ b/posts/procrun-3-unix-sessions.mdwn
@@ -0,0 +1,112 @@
+[[!meta date="Wed, 26 Apr 2017 12:00:07 +0000"]]
+[[!meta title="Is your process running 3 - UNIX sessions"]]
+[[!meta author="Richard Maw"]]
+[[!tag process job pgroup daemon kill setsid session utmp wtmp]]
+
+We previously discussed issues with using PIDfiles.
+
+One issue we encountered was that we need a way to handle multiple processes.
+
+Process groups
+===
+
+If you've ever started a program in the background in a shell
+you might have noticed it gave you a "Job ID" to refer to it
+rather than a process ID.
+
+This is not just to give you a memorable number for each task,
+but because jobs may contain multiple processes,
+which is how a pipeline of multiple processes may be a single job.
+
+This is accomplished in Linux and traditional UNIXes
+with the [setpgrp(2)][] system call
+which assigns a new process group to a process
+which will be inherited by its subprocesses.
+
+This entire process group may be killed
+by passing the negation of the process group ID
+to the [kill(2)][] system call.
+
+A process may only be part of one process group though,
+so if you have processes that may call [setpgrp(2)][] themselves
+then it is not possible to use process groups
+to manage terminating a whole process tree of a service.
+
+UNIX Sessions
+===
+
+You may be wondering how anything can possibly work
+if you can't use process groups to track a user's processes.
+
+The answer to this is that UNIX has a concept of sessions.
+
+Every process is a part of a session,
+and each session has a "controlling TTY",
+which can be accessed via `/dev/tty`.
+
+When a process creates a new session with [setsid(2)][]
+it becomes the session leader.
+
+If the session leader process is terminated
+then the entire session receives the `SIGHUP` signal,
+which by default terminates the process.
+
+The controlling tty was traditionally a [virtual terminal][]
+which emulates the old teletype terminals on modern computers.
+[Terminal windows in graphical interfaces][xterm] use [pseudo terminals][],
+which could be used to use sessions
+for grouping processes that don't belong to a device.
+
+This is typically done by [getty][] and [login(1)][], [terminal emulator][xterm]
+or [sshd][],
+which also update [utmp(5)][] to include the controlling TTY and session ID,
+to track the current active sessions.
+
+There are a number of issues with using UNIX sessions for tracking processes.
+
+1.  [utmp(5)][] is an awkward interface,
+    requiring multiple processes to access a single file
+    without trampling over each other,
+    requiring file range locking,
+    which can't be done portably and in a thread-safe manner.
+
+    I consider this to be analogous to [/etc/mtab][mtab],
+    which was an old, manually maintained file,
+    which had to be replaced with a more reliable, kernel-provided interface.
+
+2.  [setsid(2)][] describes sessions and process groups
+    as a strict two-level hierarchy.
+
+    The implication of this is that any process can escape with [setsid(2)][],
+    so bypassing [mtab][]
+    and inspecting the contents of the `sessionid` flie in `/proc` won't work.
+
+3.  Escaping session cleanup is by necessity a well-documented procedure,
+    since traditional daemons are started by detaching from the current session
+    rather than asking the [init][] process to start the daemon.
+
+    See [nohup(1)][] for details about how to escape session cleanup.
+
+Conclusion
+===
+
+The traditional UNIX system calls came from a time
+when it was believed you could trust programs to be well written and benign.
+
+We do not live in this world,
+so we need a better approach to track which processes we run on our computers,
+which we will discuss in a future article.
+
+[kill(2)]: http://man7.org/linux/man-pages/man2/kill.2.html
+[setsid(2)]: http://man7.org/linux/man-pages/man2/setsid.2.html
+[setpgrp(2)]: http://man7.org/linux/man-pages/man2/setpgrp.2.html
+[virtual terminal]: https://en.wikipedia.org/wiki/Virtual_terminal
+[pseudo terminals]:  https://en.wikipedia.org/wiki/Pseudoterminal
+[xterm]: https://en.wikipedia.org/wiki/Xterm
+[getty]: https://en.wikipedia.org/wiki/Getty_(Unix)
+[login(1)]: http://man7.org/linux/man-pages/man1/login.1.html
+[sshd]: https://linux.die.net/man/8/sshd
+[utmp(5)]: http://man7.org/linux/man-pages/man5/utmp.5.html
+[mtab]: https://en.wikipedia.org/wiki/Mtab
+[init]: https://en.wikipedia.org/wiki/Init
+[nohup(1)]: http://man7.org/linux/man-pages/man1/nohup.1.html

publishing
diff --git a/posts/motivation.mdwn b/posts/motivation.mdwn
new file mode 100644
index 0000000..f72f425
--- /dev/null
+++ b/posts/motivation.mdwn
@@ -0,0 +1,56 @@
+[[!meta date="Wed, 19 Apr 2017 11:24:16 +0000"]]
+[[!meta title="Find your motivation"]]
+[[!meta author="Daniel Silverstone"]]
+[[!tag motivation]]
+
+A [while ago][] I wrote about ensuring that you know why you're writing
+something in order that you keep focussed on that goal while you code.  My
+focus at that point was on the specific project you were looking to undertake,
+but it may behoove us to look at the wider picture from time to time.
+
+> What motivates you?
+> ===================
+
+It's important that you can answer this question, ideally without hesitation or
+backtracking.  For each of us the answer will be different, and noone's answer
+is any less "right" than anyone elses.  For myself, it took several years to be
+in a position to answer the question confidently, quickly, and consistently.
+That's not to say that my answer won't change in the future, but at least for
+now I know what motivates me and how that manifests in my day-to-day hacking.
+
+I have had a word with [Richard][] and he has explained his motivation to me,
+and so for your perusal and criticism, here's what motivates us both..
+
+Daniel
+------
+
+For me, the primary motivation for writing free software is that I enjoy making
+it possible for other people to achieve things.  I am, as it were, an "enabler"
+or "facilitator".  This manifests itself in an interest in processes,
+meta-programming, and tooling.  I find myself writing libraries, services, and
+test tooling; and I enjoy reading papers and architecture designs, thinking of
+new ways to solve old problems, and novel problems to solve.  (And of course,
+I write articles on this here blog :-) )
+
+Richard
+-------
+
+> My motivation in general is to learn something such that it can be applied to
+> something which in some way may be construed as to the betterment of society.
+> Or indeed those things which may improve society directly.  In the
+> free-software world, this has manifested in the topic of reliability and also
+> freeing people from vendor lock-in.
+
+(* note, I kinda paraphrased what Richard said)
+
+Homework
+========
+
+You didn't think I'd let you get away with no homework this week did you?  Hah!
+I'd like you to sit down, consider your motivation in the free software world
+and a few ways in which that manifests into projects you work on or with.  If
+you're feeling super-enthusiastic about it, why not post a comment on this post
+and share your motivation with the rest of us?
+
+[while ago]: /posts/truism-1-if-you-dont-know-why/
+[Richard]: /bio/richard/

creating tag page tags/kill
diff --git a/tags/kill.mdwn b/tags/kill.mdwn
new file mode 100644
index 0000000..fa993d4
--- /dev/null
+++ b/tags/kill.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged kill"]]
+
+[[!inline pages="tagged(kill)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/pidfile
diff --git a/tags/pidfile.mdwn b/tags/pidfile.mdwn
new file mode 100644
index 0000000..306be28
--- /dev/null
+++ b/tags/pidfile.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged pidfile"]]
+
+[[!inline pages="tagged(pidfile)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/proc
diff --git a/tags/proc.mdwn b/tags/proc.mdwn
new file mode 100644
index 0000000..03ad548
--- /dev/null
+++ b/tags/proc.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged proc"]]
+
+[[!inline pages="tagged(proc)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/procrun-2-pidfiles.mdwn b/posts/procrun-2-pidfiles.mdwn
new file mode 100644
index 0000000..710b3d0
--- /dev/null
+++ b/posts/procrun-2-pidfiles.mdwn
@@ -0,0 +1,196 @@
+[[!meta date="Wed, 19 Apr 2017 11:20:30 +0000"]]
+[[!meta title="Is your process running 2 - Nobody does pidfiles right"]]
+[[!meta author="Richard Maw"]]
+[[!tag process systemd daemon pidfile proc kill flock]]
+
+Previously we lamented that we had to read the `cmdline` for every process
+to work out whether the program we want to run is already running,
+and that we'd like to be able to look up a name to see if it's running.
+
+The traditional way to do this
+is to write the [process identifier (or PID)][PID]
+to a file called named after your program,
+such as `/var/run/$PROGNAME.pid`.
+
+This is an obvious solution, that you will probably have seen before,
+and before [systemd][] and [upstart][] became popular,
+was _the_ way you handled running services in Linux.
+
+How people do pid files wrong
+===
+
+On the surface just writing the [PID][] looks like a good idea,
+since you can use the presence of the file to tell that the process is running
+or read the contents of the file to see which [PID][] it's using
+so you can [kill(2)][] the process.
+
+This however is less reliable than parsing files in [procfs][],
+since if you're reading from `/proc` you know it's *always* up to date
+since it's provided by the kernel's process table.
+
+There are no such guarantees from the [PID][] file.
+Your process could terminate abnormally and not clean it up.
+
+Be extra cautious with [PID][] files not stored in `/run` or `/var/run`,
+since there is no guarantee that they weren't left over from a previous boot.
+
+Reliability can be improved
+by checking whether the [PID][] from the file is in use,
+by running [kill][kill(2)]`(pid, 0) == 0` in C,
+or [kill][kill(1)]` -0 $pid` in shell,
+since this will evalutate to true if that process is running.
+
+This is not yet reliable though,
+since while killing with signal 0 will tell you
+whether a process with that [PID][] is running,
+you can't tell if it's the *correct* process,
+since [PID][]s get reused fairly frequently.
+
+For [PID][] files to be reliable
+you need some way to guarantee that the [PID][] in the file
+is actually referring to the correct process.
+
+You need some way of tying the lifetime of the process to the file.
+
+When a process terminates all the file descriptors it had open are closed,
+so we can know that the contents are valid if a process is holding it open.
+
+You may be tempted to use [lsof][lsof(1)]` -Fp -f -- /var/run/$PROGNAME.pid`,
+or parsing [procfs][] manually to determine whether a process is using the file,
+but this is awkward for the same reason
+as not parsing the output of the [ps(1)][] command to tell whether it's running.
+
+We need to be able to do something to the file descriptor
+that will have an observable effect through other file descriptors to that flie.
+
+The solution to this is to take a lock on the file.
+
+You may see some programs use [fcntl(2)][] with `F_SETLK`.
+This is tempting because `F_GETLK` will include the [PID][] in the result
+instead of requiring the service to serialise and write the [PID][] to the flie
+and the checking process having to read and parse the file.
+
+`F_SETLK` should be avoided because the lock is removed
+when *any* file descriptor to that file owned by that process is closed,
+so you need to be able to guarantee
+that neither any of your code not any other code you use via a library
+will ever open that [PID][] file again
+even if your process normally opens arbitrary files by user input.
+
+So rather than using [fcntl(2)][] with `F_SETLK`,
+use [flock(2)][] with `LOCK_EX`, or [fcntl(2)][] with `F_WRLK`
+to take a write or exclusive lock on the file,
+and test whether the contents are live by trying to take a read or shared lock,
+with [flock(2)][]'s `LOCK_SH`, or [fcntl(2)][]'s `F_RDLK`.
+
+If you succeed at taking a read lock then the contents of the file aren't valid
+and the service isn't running.
+
+Implementing this logic can be awkward,
+fortunately if you're writing a C program
+you can use the [libbsd-pidfile][] functions.
+
+It's the wrong tool for the job
+===
+
+Setting it up correctly is tricky
+---
+
+The [libbsd-pidfile][] functions will handle locks correctly,
+but as permissively licensed as it is,
+it is not always available, perticularly if you're not writing a C program.
+
+A brief survey of the top results for python libraries for handling PID files
+resulted in [pid][trbspid], [python-pidfile][] and [pidfile][pypidfile].
+
+[python-pidfile][] does not keep the file open or take a lock.
+[pidfile][pypidfile] only improves by taking the lock and holding it.
+[pid][trbspid] checks the validity and sets correct permissions on the file.
+None of them have a mechanism to safely retrieve the [PID][] from the file.
+
+So if you have to do it yourself,
+you'll need to do the following:
+
+1.  open with `O_CREAT` to make the lock file if it doesn't exist.
+2.  Try to non-blocking take a shared lock on the file.
+    If you fail it's running,
+    and depending on whether you want to end it, replace it or leave it,
+    you should either instruct it to
+    terminate and continue, exit, or terminate then exit.
+    If you succeed then it's not running.
+3.  If you want to start a new service or replace it,
+    upgrade your shared lock to an exclusive lock **with a timeout**.
+    If you take a blocking lock then your processes will deadlock
+    waiting for their turn to start the service,
+    and if you take a non-blocking lock then
+    if your process is pre-empted by another process between trying to lock
+    and releasing the shared lock,
+    then you could end up with every process exiting.
+4.  If you took the lock replace the contents of the file with your [PID][],
+    if you timed out unlock the file or exit.
+
+The above is already complicated and still doesn't handle edge-cases,
+such as another process trying to start
+between taking the lock and writing the [PID][],
+which [libbsd-pidfile][] handles with a retry loop.
+
+It also doesn't handle the file being [unlink][unlink(2)]ed while starting,
+which would cause you to have multiple services running.
+
+[libbsd-pidfile][] doesn't take the shared lock then upgrade,
+so if many processes often want to know whether it's running,
+then they would be unnecessarily contesting the lock.
+
+Views of PIDs are not universal
+---
+
+[Process namespaces][pidns] exist.
+
+While a single process' view of its [PID][] does not change,
+other processes can see it with different [PID][]s
+since processes in sub-namespaces are viewable in multiple namespaces
+and have a different [PID][] in each namespace.
+
+You can detect whether the process is running by whether locking fails,
+but you can't use the contents to terminate it,
+since the PID it knows it to be is different from the PID you can reach it with,
+unless you use [a restricted system call][setns(2)]
+to enter the namespace of the process
+in order to terminate it.
+
+[fcntl(2)][]'s `F_GETLK` would return the [PID][] correctly,
+but is unreliable in other areas.
+
+Services can span more than one process
+---
+
+The PIDfile model works acceptably if your service only runs in one process,
+but some programs spawn helper processes
+and terminating the lead process may not tidy up all the helper processes.
+
+There are ways to have the termination of one process
+cause the termination of others,
+however this just moves the problem of "how do you know your process is running"
+to the supervising process without solving the general problem.
+
+So, we know that PID files aren't necessarily the right tool for the job,
+in the next article we explore some alternatives.
+
+[PID]: https://en.wikipedia.org/wiki/Process_identifier
+[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
+[upstart]: http://upstart.ubuntu.com/
+[kill(2)]: http://man7.org/linux/man-pages/man2/kill.2.html
+[procfs]: http://man7.org/linux/man-pages/man5/proc.5.html
+[flock(2)]: http://man7.org/linux/man-pages/man2/flock.2.html
+[fcntl(2)]: http://man7.org/linux/man-pages/man2/fcntl.2.html
+[libbsd-pidfile]: https://manpages.debian.org/testing/libbsd-dev/pidfile.3.en.html
+[pidns]: http://man7.org/linux/man-pages/man7/pid_namespaces.7.html
+[unlink(2)]: http://man7.org/linux/man-pages/man2/unlink.2.html
+[setns(2)]: http://man7.org/linux/man-pages/man2/setns.2.html
+[kill(2)]: http://man7.org/linux/man-pages/man2/kill.2.html
+[kill(1)]: http://man7.org/linux/man-pages/man1/kill.1.html
+[ps(1)]: http://man7.org/linux/man-pages/man1/ps.1.html
+[lsof(1)]: http://man7.org/linux/man-pages/man1/lsof.1.html
+[trbspid]: https://github.com/trbs/pid/

(Diff truncated)
Tweak my bio
diff --git a/bio/daniel.mdwn b/bio/daniel.mdwn
index 5381e8e..6e281ce 100644
--- a/bio/daniel.mdwn
+++ b/bio/daniel.mdwn
@@ -1,6 +1,6 @@
 # Daniel Silverstone
 
-Daniel Silverstone is a Senior Software Developer at [Codethink] and was
+Daniel Silverstone is a Solution Architect at [Codethink] (whatever that means) and was
 fundamental to the original concept of [Baserock].  Daniel studied computer
 science with cognitive sciences at [University College London][ucl] for a year before
 giving up and going into games development.

creating tag page tags/testing
diff --git a/tags/testing.mdwn b/tags/testing.mdwn
new file mode 100644
index 0000000..8507783
--- /dev/null
+++ b/tags/testing.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged testing"]]
+
+[[!inline pages="tagged(testing)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/workflow
diff --git a/tags/workflow.mdwn b/tags/workflow.mdwn
new file mode 100644
index 0000000..4028013
--- /dev/null
+++ b/tags/workflow.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged workflow"]]
+
+[[!inline pages="tagged(workflow)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/scaffolding
diff --git a/tags/scaffolding.mdwn b/tags/scaffolding.mdwn
new file mode 100644
index 0000000..5a749b2
--- /dev/null
+++ b/tags/scaffolding.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged scaffolding"]]
+
+[[!inline pages="tagged(scaffolding)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/packaging
diff --git a/tags/packaging.mdwn b/tags/packaging.mdwn
new file mode 100644
index 0000000..7b690ab
--- /dev/null
+++ b/tags/packaging.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged packaging"]]
+
+[[!inline pages="tagged(packaging)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/new-project
diff --git a/tags/new-project.mdwn b/tags/new-project.mdwn
new file mode 100644
index 0000000..1bf0368
--- /dev/null
+++ b/tags/new-project.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged new-project"]]
+
+[[!inline pages="tagged(new-project)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/scaffolding.mdwn b/posts/scaffolding.mdwn
new file mode 100644
index 0000000..ecac78a
--- /dev/null
+++ b/posts/scaffolding.mdwn
@@ -0,0 +1,63 @@
+[[!meta date="Wed, 05 Apr 2017 11:00:06 +0000"]]
+[[!meta title="New project? Start with the scaffolding"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag new-project project scaffolding testing packaging workflow]]
+
+So you're starting a new project. You have an idea for something, and
+a vision for how to implement it. What should you do first?
+
+If you're like me, you burn to start with the interesting coding bit
+first. After a few hours of furious typing, you've done the fun bit,
+and you need to add all the boring bits: automated tests (unless you
+did TDD, and even then there may be missing tests), documentation, a
+manual page, a README, perhaps packaging (Debian, RPM, language
+specific), a CI project, a home page, etc. There's a lot of it. That
+is usually when my enthusiasm fades. A lot of my projects end up as a
+single file in `~/bin`.
+
+I call the boring bits scaffolding, and I've learnt that it pays to do
+them first. Not only is that often the only time I will actually do
+them, but once the scaffolding is in place, the fun bits are also more
+fun to do.
+
+If I have unit and integration test frameworks in place, adding
+another test is only a small incremental task. If I haven't got them
+in place (particularly for integration tests), I tend to postpone
+writing tests. No chance of TDD, whereas when I put in an integration
+test framework, I often to TDD at the program level, not just at the
+individual class and method level.
+
+Likewise, if I start by writing a manual page, adding another sentence
+or paragraph is easy. Also, writing a manual page, or any
+documentation, clarifies my thinking about what the program should
+actually do, and how it should be used. This makes writing the code
+more pleasant.
+
+Having CI in place from the beginning, means the tests I write get
+exercised from the start. This finds bugs earlier, even if I run my
+tests manually as well. CI never thinks "I can run test faster this
+one time by taking this clever shortcut".
+
+Of course, putting up a lot of scaffolding takes effort, and it's all
+wasted if you don't actually want to write the program after all.
+Sometimes what sounds like a brilliant idea on the last train home
+from a party, makes no sense at all in the morning. (Personal
+experience, ahem.)
+
+Thus it may make sense to start with a simple proof of concept, or
+prototype implementation to verify the soundness of you idea, then
+throw that away, and set up scaffolding, before you start writing
+production code.
+
+My latest personal project has a manual page, unit and integration
+tests, Debian packaging, a CI project, and a home page. I can install
+it and run it. It does't yet do anything useful. Before all this, I
+wrote a prototype to prove the idea I had, and threw that away. Some
+time this year I will start dropping in modules to actually do useful
+stuff, and that'll be easy, since I won't need to worry about all the
+boring bits. As soon as it does anything useful, I can also point
+friends at a Debian package and ask them to try my latest masterpiece.
+
+What's more, I have a better chance of getting them to help by writing
+a module they need themselves, since they just need to write the
+module and don't need to worry about the rest.

creating tag page tags/tty
diff --git a/tags/tty.mdwn b/tags/tty.mdwn
new file mode 100644
index 0000000..5692b84
--- /dev/null
+++ b/tags/tty.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged tty"]]
+
+[[!inline pages="tagged(tty)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/recording
diff --git a/tags/recording.mdwn b/tags/recording.mdwn
new file mode 100644
index 0000000..1c66a9c
--- /dev/null
+++ b/tags/recording.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged recording"]]
+
+[[!inline pages="tagged(recording)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/web
diff --git a/tags/web.mdwn b/tags/web.mdwn
new file mode 100644
index 0000000..22374a1
--- /dev/null
+++ b/tags/web.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged web"]]
+
+[[!inline pages="tagged(web)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/recording-your-terminal.mdwn b/posts/recording-your-terminal.mdwn
new file mode 100644
index 0000000..16bf473
--- /dev/null
+++ b/posts/recording-your-terminal.mdwn
@@ -0,0 +1,92 @@
+[[!meta date="Wed, 29 Mar 2017 11:00:06 +0000"]]
+[[!meta title="Sweetie! You're gonna be a movie star! - Recording your Terminal"]]
+[[!meta author="Daniel Silverstone"]]
+[[!tag tty recording web]]
+
+From time to time, you write something which you really want to show off.  If
+it's a GUI application then you might start with some good screenshots, or
+possibly even make a screen-capture video of you using the application, so that
+people can watch and marvel at your amazing creation.
+
+If your wonderful program happens to be a command-line tool, then such videos
+are often a little lackluster or simply overly-large for the information they
+convey.  It's better if the text being displayed is actually text and that it
+can be copy-pasted out (so others can follow along in their own terminals).  To
+that end, there is a number of tools for recording operations in a terminal and
+allowing that to played back.  I will mention a few of them here, but this is
+by no means an exhaustive list; and I shall endeavour to not recommend any
+specific option over any other.
+
+Asciinema
+---------
+
+Asciinema is a pretty slick project housed at <https://asciinema.org/> with its
+source available at <https://github.com/asciinema/asciinema> and
+<https://github.com/asciinema/asciinema-player>.  Asciinema is available in
+[Debian][] and other Linux distributions and works very well.  The Asciinema
+community provides a hosted system and also the tooling necessary to provision
+the playback of recordings on your own website providing you can honour the
+[GPLv3][].  The client application is written in Python and has few
+dependencies.
+
+You can see an example at: <https://asciinema.org/a/42383>
+
+showterm
+--------
+
+Like Asciinema, showterm provides a hosted service, over at
+<https://showterm.io/> and an open-source tool hosted at
+<https://github.com/ConradIrwin/showterm>.  Showterm's server-side is also
+open, but is focussed on a hosted experience so expect to be running up a rails
+app if you want to host it yourself.
+
+Showterm is written in Ruby and is under the MIT licence as is its server.  It
+also relies on `ttyrec` in some circumstances.
+
+You can see an example at: <https://showterm.io/7b5f8d42ba021511e627e>
+
+TermRecord
+----------
+
+If you're hoping for standalone HTML output, then TermRecord might be what
+you're after.  It can be found at <https://github.com/theonewolf/TermRecord>
+and is written in Python.  Unlike the other offerings, TermRecord produces
+entirely standalone output which doesn't depend on any other JavaScript or
+server resources.
+
+The licence terms for the TermRecord output include MIT licensed JavaScript,
+and font content under the Ubuntu Font License 1.0.
+
+You can see an example at: <http://theonewolf.github.io/TermRecord/figlet-static.html>
+
+TTYGIF
+------
+
+The TTYGIF project deserves an honourable mention because despite its output
+not being copy/pasteable; an animated GIF is much smaller than a video file
+would likely be.  TTYGIF is housed at <https://github.com/icholy/ttygif> and
+produces a simple animated [GIF][] of the terminal it is running in.  Since
+almost every web browser which isn't purely text-based offers animated GIF
+playback, the output of TTYGIF doesn't need any additional support.  No
+JavaScript players or complex plugins.
+
+TTYGIF is MIT licensed, but doesn't seem to place any particular licence on
+its output.  It's also written in C and needs a few dependencies to get itself
+going, one of which is a tty recorder anyway :-)
+
+You can see an example at: <https://camo.githubusercontent.com/acff4cc740350a784cb4539e501fcce1815329c0/687474703a2f2f692e696d6775722e636f6d2f6e76454854676e2e676966>
+
+Others
+------
+
+There are plenty of other options, including those which tend to only offer
+playback in a terminal themselves, such as `script` and `ttyrec`.  Your
+homework (You didn't think you'd got away with another week without homework
+did you?) is to have a play with some of the options listed here (or any
+others) you can find, and then perhaps comment on this posting showing what
+you've managed to get up to while creating a tty-cast to demonstrate your
+latest impressive terminal skills.
+
+[Debian]: https://www.debian.org/
+[GPLv3]: https://www.gnu.org/licenses/quick-guide-gplv3.en.html
+[GIF]: https://en.wikipedia.org/wiki/GIF

Fix weird paragraph formatting.
It looks reasonable as text,
but list items with multiple paragraphs get formatted differently,
and it switches only at the last item,
so give wider spacing to the rest too.
diff --git a/posts/procrun-1-parsing-proc.mdwn b/posts/procrun-1-parsing-proc.mdwn
index d2ea8f0..7496f00 100644
--- a/posts/procrun-1-parsing-proc.mdwn
+++ b/posts/procrun-1-parsing-proc.mdwn
@@ -84,16 +84,20 @@ but as usual caveats apply:
 1.  Not all processes have an initial executable.
     This symbolic link may be unreadable (fails with [errno][] of `ENOENT`)
     in the case of kernel threads.
+
 2.  It could be a program that has subcommands,
     one of which may be a long-running service (e.g. git-daemon),
     which you wouldn't want to fail to start
     just because a shorter operation with a different subcommand
     happened to be running at the same time.
+
 3.  This is unhelpful in the case of interpreted languages,
     since it is always the name of the interpreter
     rather than the name of the script.
+
 4.  The same program may be reachable by multiple file paths
     if the executable has been hard-linked.
+
 5.  If the program's executable may be removed while it is running,
     changing `exe` to append " (deleted)" to the file path.
 

Fix typo in executable
diff --git a/posts/procrun-1-parsing-proc.mdwn b/posts/procrun-1-parsing-proc.mdwn
index b25c0d8..d2ea8f0 100644
--- a/posts/procrun-1-parsing-proc.mdwn
+++ b/posts/procrun-1-parsing-proc.mdwn
@@ -94,7 +94,7 @@ but as usual caveats apply:
     rather than the name of the script.
 4.  The same program may be reachable by multiple file paths
     if the executable has been hard-linked.
-5.  If the program's execuable may be removed while it is running,
+5.  If the program's executable may be removed while it is running,
     changing `exe` to append " (deleted)" to the file path.
 
     If this file is then replaced

Fix up nonsense sentence
diff --git a/posts/procrun-1-parsing-proc.mdwn b/posts/procrun-1-parsing-proc.mdwn
index af1d864..b25c0d8 100644
--- a/posts/procrun-1-parsing-proc.mdwn
+++ b/posts/procrun-1-parsing-proc.mdwn
@@ -87,7 +87,8 @@ but as usual caveats apply:
 2.  It could be a program that has subcommands,
     one of which may be a long-running service (e.g. git-daemon),
     which you wouldn't want to fail to start
-    just because a long operation with a different subcommand.
+    just because a shorter operation with a different subcommand
+    happened to be running at the same time.
 3.  This is unhelpful in the case of interpreted languages,
     since it is always the name of the interpreter
     rather than the name of the script.

creating tag page tags/process
diff --git a/tags/process.mdwn b/tags/process.mdwn
new file mode 100644
index 0000000..13e0ef2
--- /dev/null
+++ b/tags/process.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged process"]]
+
+[[!inline pages="tagged(process)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/procrun-1-parsing-proc.mdwn b/posts/procrun-1-parsing-proc.mdwn
new file mode 100644
index 0000000..af1d864
--- /dev/null
+++ b/posts/procrun-1-parsing-proc.mdwn
@@ -0,0 +1,138 @@
+[[!meta date="Wed, 22 Mar 2017 12:00:08 +0000"]]
+[[!meta title="Is your process running 1 - Parsing proc and why you shoudn't"]]
+[[!meta author="Richard Maw"]]
+[[!tag process systemd daemon]]
+
+Sometimes it is necessary to leave a process running,
+performing some service in the background while doing something else.
+
+It would be redundant and possibly harmful
+to start a new one if it is already running.
+
+Ideally all programs would safely shut themselves down if already running,
+checking if it's running before starting
+only guarantees that it was runing when you checked,
+rather than that it is running when you need it.
+For most purposes though it is reasonable to check first.
+
+So how do we know if our service is running?
+
+You may have run [ps(1)][] before to see if a process is running,
+so you might naturally think this would be how to do it.
+
+This would of course fall into the trap of parsing the output of shell commands.
+Why should we write fragile code
+when [ps(1)][] is using a proper API to do it?
+
+The way this is accomplished
+is the [procfs][] [virtual file system][] traditionally [mounted][] at `/proc`.
+There is a subdirectory in this file system for each process
+listed by its process ID.
+
+We can list all directories that are processes by running:
+
+    find /proc -mindepth 1 -maxdepth 1 -name '[0-9]*'
+
+Inside each of these directories are files describing the process.
+
+Check `comm`
+===
+
+When you look at the output of [`ps`][ps(1)]
+it shows the name of the process,
+which is normally the base name of the file path
+of the executable that the process was started with.
+
+This is stored in the file in `/proc` called `comm`.
+
+So if the name of your program is "myprogram",
+you can find out if your program is running with the following command:
+
+    find /proc -mindepth 1 -maxdepth 1 ! -name '*[^0-9]*' -type d -exec sh -c \
+        '[ "$(cat "$1/comm")" = myprogram ] && echo Is running' - {} ';'
+
+I would recommend against checking if your program is running this way though,
+as processes may call themselves whatever they want,
+by writing the new name to `comm`.
+
+    $ cat /proc/$$/comm
+    bash
+    $ printf dash >/proc/$$/comm
+    $ cat /proc/$$/comm
+    dash
+
+This is often used by services that fork off helper processes
+to name the subprocesses after their role
+to make it easier for developers or sysadmins to know what they do.
+
+Check `exe`
+===
+
+The [procfs][] entry also includes
+the path of the executable the proccess was started from
+as a symbolic link.
+
+Thus if your program is installed at `/usr/bin/myprogram`
+then we can check whether it is running with:
+
+    find /proc -mindepth 1 -maxdepth 1 ! -name '*[^0-9]*' -type d -exec sh -c \
+        '[ "$(readink "$1/exe")" = /usr/bin/myprogram ] && echo Is running' - {} ';'
+
+This cannot be modified by the proces after it has started,
+but as usual caveats apply:
+
+1.  Not all processes have an initial executable.
+    This symbolic link may be unreadable (fails with [errno][] of `ENOENT`)
+    in the case of kernel threads.
+2.  It could be a program that has subcommands,
+    one of which may be a long-running service (e.g. git-daemon),
+    which you wouldn't want to fail to start
+    just because a long operation with a different subcommand.
+3.  This is unhelpful in the case of interpreted languages,
+    since it is always the name of the interpreter
+    rather than the name of the script.
+4.  The same program may be reachable by multiple file paths
+    if the executable has been hard-linked.
+5.  If the program's execuable may be removed while it is running,
+    changing `exe` to append " (deleted)" to the file path.
+
+    If this file is then replaced
+    then another process may have the same executable path
+    but an incompatible behaviour.
+    
+    This isn't even unusual if the name of the process is generic,
+    like "sh" or "httpd".
+
+So it's useless for interpreted programs
+and unreliable if the executable can be replaced.
+
+Check `cmdline`
+===
+
+It could be perfectly safe to run the same program multiple times
+provided it is passed different configuration.
+
+The `cmdline` file can be parsed to infer this configuration
+as a list of strings that are NUL terminated.
+
+A problem with this approach
+is the need to reimplement parsing logic
+*and* know for all command-lines whether it's appropriate to start another.
+
+This logic could be quite difficult,
+but you could add a parameter just for determining whether it is the same.
+
+This is far from ideal because:
+
+1.  Lookup time gets worse as your system has more processes running.
+2.  Processes can modify their command-line too,
+    so another process could arrange to have the same command-line,
+    and make this unreliable.
+
+Next time we are going to look at a better use for that parameter.
+
+[ps(1)]: http://man7.org/linux/man-pages/man1/ps.1.html
+[procfs]: http://man7.org/linux/man-pages/man5/proc.5.html
+[virtual file system]: https://en.wikipedia.org/wiki/Virtual_file_system
+[mounted]: https://en.wikipedia.org/wiki/Mount_(computing)
+[errno]: http://man7.org/linux/man-pages/man3/errno.3.html

creating tag page tags/it-worked-a-month-ago
diff --git a/tags/it-worked-a-month-ago.mdwn b/tags/it-worked-a-month-ago.mdwn
new file mode 100644
index 0000000..92b907e
--- /dev/null
+++ b/tags/it-worked-a-month-ago.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged it-worked-a-month-ago"]]
+
+[[!inline pages="tagged(it-worked-a-month-ago)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/bitrot
diff --git a/tags/bitrot.mdwn b/tags/bitrot.mdwn
new file mode 100644
index 0000000..fca2ca3
--- /dev/null
+++ b/tags/bitrot.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged bitrot"]]
+
+[[!inline pages="tagged(bitrot)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/bitrot.mdwn b/posts/bitrot.mdwn
new file mode 100644
index 0000000..04f3587
--- /dev/null
+++ b/posts/bitrot.mdwn
@@ -0,0 +1,61 @@
+[[!meta date="Wed, 15 Mar 2017 12:00:07 +0000"]]
+[[!meta title="What is this disgusting smell? On software bit rot"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag bitrot it-worked-a-month-ago]]
+
+[Bit rot]: https://en.wikipedia.org/wiki/Software_rot
+
+[Bit rot][], specifically the phenomenon of software working less well
+even if it hasn't changed, is annoying, but a fact of life. There
+might be a thing or two you can do to make it happen less.
+
+Examples from your author's personal experience from the past year:
+
+* Cloud provider changes the default username on base images from
+  `ec2-user` to `debian`, requiring simple changes needed in many
+  places.
+* Cloud provider upgrades their virtualisation platform, which
+  introduces a new API version, and breaks the old version. All API
+  using automation needs upgrading.
+* Configuration management software introduces a new feature
+  (`become`), and deprecates the old corresponding feature (`sudo`).
+  Simple changes, but in many places.
+* Configuration management software breaks the new feature (can no
+  longer switch to an unprivileged user to run shell script snippets),
+  requiring more complicated changes in several places (run shell as
+  root, invoke sudo explicitly).
+* Author's software depends on enterprise-grade software for a
+  specific service, which switches to requiring Oracle Java, instead
+  of OpenJDK. Author's software isn't fully free software anymore.
+
+Bit rot happens for various reasons. The most common reason is that
+the environment changes. For example, software that communicates over
+the network may cease to function satisfactorily if the other
+computers change. A common example is the web browser: even though
+your computer works just as well as before, in isolation, web sites
+use new features of HTML, CSS, and JavaScript, not to mention media
+formats, and web pages become bigger, and in general everything
+becomes heavier. Also, as your browser version ages, sites stop caring
+about testing with it, and start doing things that expose bugs in your
+version. Your web experience becomes worse every year. Your browser
+bit rots.
+
+There is no way to prevent bit rot. It is a constant that everything
+is variable. However, you can reduce it by avoiding common pitfalls.
+For example, avoid dependencies that are likely to change,
+particularly in ways that will break your software. An HTML parsing
+library will necessarily change, but that shouldn't break your
+software if the library provdes a stable API. If the library adds
+support for a new syntactic construction in HTML, your program should
+continue to work as before.
+
+You should be as explicit as possible in what you expect from the
+environment. Aim to use standard protocols and interfaces. Use
+standard POSIX system calls, when possible, instead of experimental
+Linux-specific ones from out-of-tree development branches. Sometimes
+that isn't possible: document that clearly.
+
+Have automated ways of testing that your software works, preferably
+tests that can be run against an installed instance. Run those tests
+from time to time. This will let you and your users notice earlier
+that something's broken.

publishing
diff --git a/posts/hiring-floss-people.mdwn b/posts/hiring-floss-people.mdwn
new file mode 100644
index 0000000..a360ad0
--- /dev/null
+++ b/posts/hiring-floss-people.mdwn
@@ -0,0 +1,49 @@
+[[!meta date="Wed, 08 Mar 2017 12:00:07 +0000"]]
+[[!meta title="What I look for in a F/LOSS applicant"]]
+[[!meta author="Daniel Silverstone"]]
+
+I have the dubious honour of being one of the people, at my place of work,
+charged with interviewing technical applicants.  Without giving the game away
+too much, I thought I might give a few hints for things I look for in a CV,
+and in the wider world, when considering and interviewing a candidate.
+
+First a little context - I tend to interview candidates who are applying for
+higher-level technical roles in the company, and I have a particular focus on
+those who claim on their CV to have a lot of experience.  I start by reading
+the cover letter and CV looking for hints of F/LOSS projects the applicant has
+worked with; either as a user or a developer.  I like it when an applicant
+provides a bitbucket, github or gitlab URL for their personal work if they have
+any; but I *really* like it when they provide a URL for their own Git server
+(as you might imagine).
+
+Once I have identified places on the Internet where I might find someone, I
+look to dig out their [internet ghosts][] and find out what they are up to in
+the wider F/LOSS world.  The best candidates show up in plenty of places, are
+easily found making nice commits which show their capability, and seem well
+spoken on mailing lists, fora, et al.  Of course, if someone doesn't show up
+on Internet searches then that doesn't count against them because to have the
+privilege of being able to work on F/LOSS is not something afforded to all; but
+if you *do* show up and you look awful it will count against you.
+
+[internet ghosts]: http://www.ibiblio.org/Dave/Dr-Fun/df9601/df960124.jpg
+
+Also remember, there's more ways to contribute than writing code.  I love it
+when I find candidates have made positive contributions to projects outside of
+just coding for them.  Help a project's documentation, or be part of mentoring
+or guide groups, and I'll likely be very pleased to talk with you.
+
+Beyond the _Internet Stalking_, I like to get my candidates to demonstrate an
+ability to compare and contrast technologies; so a good way to get on my good
+side is to mention two similar but conflicting capabilities (such as
+[Subversion][] and [Git][]) be prepared to express a preference between them,
+and be able to _defend_ that preference.
+
+[Subversion]: http://subversion.apache.org/
+[Git]: https://git-scm.com/
+
+Finally a few basic tips -- don't lie, dissemble, or over-inflate in your CV
+or cover-letter (I will likely find out) and don't let your cover letter be
+more than a single side of A4, nor your CV more than 2 sides of A4.
+
+If I ever interview you, and I find out you read this article, I will be most
+pleased indeed.  (Assuming you take on my recommendations at least :-) )

creating tag page tags/motivation
diff --git a/tags/motivation.mdwn b/tags/motivation.mdwn
new file mode 100644
index 0000000..9297e1c
--- /dev/null
+++ b/tags/motivation.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged motivation"]]
+
+[[!inline pages="tagged(motivation)" actions="no" archive="yes"
+feedshow=10]]

publishing
diff --git a/posts/facilitating.mdwn b/posts/facilitating.mdwn
new file mode 100644
index 0000000..ef24fed
--- /dev/null
+++ b/posts/facilitating.mdwn
@@ -0,0 +1,54 @@
+[[!meta date="Wed, 01 Mar 2017 12:00:07 +0000"]]
+[[!meta title="Facilitating is no less valuable than contributing"]]
+[[!meta author="Richard Maw"]]
+[[!tag contributing motivation]]
+
+FOSS projects are mostly developed on a volunteer basis.
+
+This makes the currencies by which they are developed: free time and motivation.
+
+Often times you have the free time, but not the motivation.
+Often this is not from feeling that the work isn't worth doing,
+but that you feel inadequate to do it.
+
+Don't be disheartened.
+There's plenty you can do that helps.
+
+1.  Just be there, whether in-person or online.
+
+    You can do whatever else you want while being there,
+    but it's encouraging to not be along in your endeavours.
+
+    You may even find some motivation of your own.
+
+2.  When others are talking about what they want to achieve,
+    respond enthusiastically.
+
+    It makes them more likely to follow-through and do so,
+    and in the very least makes them feel good.
+
+    This does risk making them feel worse if they never get around to it,
+    but sometimes that's sufficient to shame them into action later,
+    and other times it's sufficient to say "these things happen".
+
+3.  Engage in discussion about what others want to achieve.
+
+    It's extremely valuable for refining ideas,
+    so they can implement what they want to do better,
+    it keeps it fresh in their mind so motivation lasts longer,
+    and it leaves a clearer idea of what to do
+    so it may be completed before motivation runs out.
+
+4.  Mention what other people are doing to people who might be interested.
+
+    You could end up with anecdotes of other people thinking it's a cool idea,
+    which when relayed to people doing the work provides their own motivation.
+
+5.  Remind people of the successes they've had.
+
+    It makes people feel good about what they've already done,
+    and can put any issues they are currently struggling with into perspective.
+
+    Lars pointed out that
+    Yakking has published more than 180 articles at a rate of one per week!
+    We've managed to get this far, we can continue for a good while yet.

publishing
diff --git a/posts/be-careful-testing.mdwn b/posts/be-careful-testing.mdwn
new file mode 100644
index 0000000..abbba2e
--- /dev/null
+++ b/posts/be-careful-testing.mdwn
@@ -0,0 +1,56 @@
+[[!meta date="Wed, 22 Feb 2017 12:00:06 +0000"]]
+[[!meta title="Please be careful when you test"]]
+[[!meta author="Daniel Silverstone"]]
+
+We have [spoken][] [before][] about testing your software.  In particular we
+have mentioned how if your code isn't tested you can't be confident that it
+works.  Whe also spoke about how the technique of testing and the level at
+which you test your code will vary based on what you need to test.
+
+[spoken]: http://yakking.branchable.com/posts/truism-4-if-it-is-not-tested/
+[before]: http://yakking.branchable.com/posts/software-testing/
+
+What I'd like to talk about this time is about understanding the environment in
+which your tests exist.  Since "nothing exists in a vacuum" it is critical to
+understand that even if you write beautifully targetted tests, they still exist
+and execute within the wider context of the computer they are running on.
+
+As you are no doubt aware by now, I have a tendency to indulge in the hoary old
+developer habit of teaching by anecdote, and today is no exception to that.  I
+was recently developing some additional tests for [Gitano][] and exposed some
+very odd issues with one test I wrote.  Since I was engaged in the
+ever-satisfying process of adding tests for a previously untested portion of
+code I, quite reasonably, expected that the issue I was encountering was a bug
+in the code I was writing tests for.  I dutifully turned up the logging levels,
+sprinkled extra debug information around the associated bits of code, and
+puzzled over the error reports and debug logs for a good hour or so.
+
+[Gitano]: https://wiki.gitano.org.uk/about/what-is/
+
+Predictably, given the topic of this article, I discovered that the error in
+question made absolutely no sense given the code I was testing, and so I had to
+cast my net wider.  Eventually I found a bug in a library which Gitano depends
+on, which gave me a somewhat [hirsuite yak][] to deal with.  Once I had written
+the patch to the library, tested it, committed it, made an upstream release,
+packaged that, reported the bug in Debian, uploaded the new package to Debian,
+and got that new package installed onto my test machine - lo and behold, my
+test for Gitano ran perfectly.
+
+[hirsuite yak]: http://yakking.branchable.com/posts/debugging/
+
+This is, of course, a very particular kind of issue.  You are not likely to
+encounter this type of scenario very often, unless you also have huge tottering
+stacks of projects which all interrelate.  However you are likely to encounter
+issues where tests assume things about their environment without necessarily
+meaning to.  Shell scripts which use bashisms, or test suites which assume they
+can bind test services to particular well known (and well-used) ports are all
+things I have encountered in the past.
+
+Some test tools offer mechanisms for ensuring the test environment is "sane"
+for a value of sanity which applies only to the test suite in question.  As
+such, your homework is to go back to one of your well-tested projects and
+consider if your tests assume anything about the environment which might need
+to be checked for (outside of things which you're already checking for in order
+to build the project in the first place).  If you find any unverified
+assumptions then consider how you might ensure that, if the assumption fails,
+the user of your test suite is given a useful report on which to act.

Added a comment: You're welcome
diff --git a/suggestion-box/comment_3_2b3649f9e6a73cdf882009e9bc318b47._comment b/suggestion-box/comment_3_2b3649f9e6a73cdf882009e9bc318b47._comment
new file mode 100644
index 0000000..84169f9
--- /dev/null
+++ b/suggestion-box/comment_3_2b3649f9e6a73cdf882009e9bc318b47._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="http://liw.fi/"
+ avatar="http://cdn.libravatar.org/avatar/db5541dd6756dc8db2663b4785de58f490e13b301f4c421e20176bc7e6a5b8e4"
+ subject="You're welcome"
+ date="2017-02-18T15:19:31Z"
+ content="""
+Awwk, thank you ana. You're very kind.
+"""]]

Added a comment: Keep up the good work
diff --git a/suggestion-box/comment_2_e3608b27f5d4cfbff53f1ad11f637e5f._comment b/suggestion-box/comment_2_e3608b27f5d4cfbff53f1ad11f637e5f._comment
new file mode 100644
index 0000000..9459db0
--- /dev/null
+++ b/suggestion-box/comment_2_e3608b27f5d4cfbff53f1ad11f637e5f._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="ana@0d0ca1cf7a8ced0d9b9ac70c133c2ca672f5a077"
+ nickname="ana"
+ avatar="http://cdn.libravatar.org/avatar/a77ac42cd26e7b41c18bafaf4c3812af"
+ subject="Keep up the good work"
+ date="2017-02-18T13:49:45Z"
+ content="""
+Folks, I have been reading yakking for 3? 4? years now and your articles have been a very valuable source to refer to co-workers and friend when they were asking about some topics. And even for relearning about some topics myself. Thank you!
+"""]]

Fix typo (quantified)
diff --git a/posts/tips-from-fosdem.mdwn b/posts/tips-from-fosdem.mdwn
index ba64b8a..59921f8 100644
--- a/posts/tips-from-fosdem.mdwn
+++ b/posts/tips-from-fosdem.mdwn
@@ -35,7 +35,7 @@ and some specific cultural differences that often cause issue.
 
 It started out with a metric by which cultural attitudes
 about 6 supposed characteristics of culture
-can be quantised
+can be quantified
 so the difference between cultural attitudes can be measured.
 
 The speaker admitted that they weren't an expert on the topic

creating tag page tags/fosdem
diff --git a/tags/fosdem.mdwn b/tags/fosdem.mdwn
new file mode 100644
index 0000000..ded7c7f
--- /dev/null
+++ b/tags/fosdem.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged fosdem"]]
+
+[[!inline pages="tagged(fosdem)" actions="no" archive="yes"
+feedshow=10]]