Recent changes to this wiki:

Fix from dks
diff --git a/posts/working-environment.mdwn b/posts/working-environment.mdwn
index 0463db0..ad3d15c 100644
--- a/posts/working-environment.mdwn
+++ b/posts/working-environment.mdwn
@@ -12,7 +12,7 @@ about how my heating boiler died at home and I had to spend two weeks with a
 computer room which was consistently below 10 degrees celsius unless I spent a
 lot of electricity heating it up.  Sitting in the cold at my keyboard was
 difficult.  You can put jumpers on, and generally keep yourself warm, but for
-at least some of, our hands still get cold, and that can be quite unpleasant
+at least some of us, our hands still get cold, and that can be quite unpleasant
 when you're a keyboard worker.
 
 The temperature of your working/hacking/playing environment will affect your

publishing
diff --git a/posts/working-environment.mdwn b/posts/working-environment.mdwn
new file mode 100644
index 0000000..0463db0
--- /dev/null
+++ b/posts/working-environment.mdwn
@@ -0,0 +1,55 @@
+[[!meta date="Wed, 13 Dec 2017 12:00:10 +0000"]]
+[[!meta title="Your working environment matters"]]
+[[!meta author="Daniel Silverstone"]]
+
+We've [previously][] spoken about how your workstation area matters, mentioning
+topics such as consistency in input surfaces, arrangement of screens, good
+chairs, etc.  Today I'd like to extend that to talk about the general
+environment in which you're working/hacking/playing.
+
+As with all these little articles, I have a story to tell, and this one is
+about how my heating boiler died at home and I had to spend two weeks with a
+computer room which was consistently below 10 degrees celsius unless I spent a
+lot of electricity heating it up.  Sitting in the cold at my keyboard was
+difficult.  You can put jumpers on, and generally keep yourself warm, but for
+at least some of, our hands still get cold, and that can be quite unpleasant
+when you're a keyboard worker.
+
+The temperature of your working/hacking/playing environment will affect your
+effectiveness dramatically.  If it's too cold, or too warm, you will not be
+able to think properly and your reaction times will grow.  Keeping the area
+around your workstation clear of clutter will also improve your ability to
+think, though some do benefit from having one or two fiddling things for when
+you need to do something with your hands while your brain wanders off to solve
+the problem.
+
+I recommend ensuring that there's not too much in the way of noise distraction
+at your workstation too.  Music is something that some of us find helps, as can
+a [white noise generator][] or [rain generator][].  I sometimes use an
+[internet cat][] to help me relax, but it's important to try and block out
+sounds which you cannot predict or control such as building site noise, other
+people talking, etc.
+
+For me, it's also important to try and eliminate unexpected or unpleasant
+scents from your workstation too.  I find that I cannot concentrate if I can
+smell food (sometimes a big issue because my neighbours love to fry onions at
+times of day when I'm hungry).
+
+Keep hydrated.  While that's not entirely an environmental thing, ensuring that
+you have an adequate supply of water, squash, tea, or whatever you prefer, is
+very important.  Bad hydration causes your brain to behave similarly to being
+drunk or super-tired.  Obviously if you're going to keep hydrated, don't try
+and sit and work through a full bladder, that can be just as
+distracting/unhelpful.
+
+Your homework for this week is to look critically at your work/hack/play
+environment and make at least one small change for the better.  Perhaps you
+could comment below about a change you made and how you feel it has affected
+you, either positively or negatively.  If you have other tips for improving
+your work/hack/play space then also include them below.
+
+
+[previously]: /posts/work-hack-play/
+[white noise generator]: https://mynoise.net/NoiseMachines/whiteNoiseGenerator.php
+[rain generator]: https://mynoise.net/NoiseMachines/rainNoiseGenerator.php
+[internet cat]: https://purrli.com/

publishing
diff --git a/posts/property-testing-in-c.mdwn b/posts/property-testing-in-c.mdwn
new file mode 100644
index 0000000..ba01355
--- /dev/null
+++ b/posts/property-testing-in-c.mdwn
@@ -0,0 +1,216 @@
+[[!meta date="Wed, 06 Dec 2017 12:00:07 +0000"]]
+[[!meta title="Property Testing in C"]]
+[[!meta author="Richard Ipsum"]]
+
+One nice thing about [Haskell][] is [Quickcheck][], if you're not familiar with
+Haskell or Quickcheck it works like this:
+
+[[!format haskell """
+Prelude> let evens xs = [ x | x <- xs, x `mod` 2 == 0 ]
+Prelude> evens [1..10]
+[2,4,6,8,10]
+"""]]
+
+Here we define a function that takes a list of numbers and returns only
+the even numbers. We can use Quickcheck to test this function:
+
+[[!format haskell """
+Prelude> import Test.QuickCheck
+Prelude Test.QuickCheck> let test_evens xs = [ x | x <- evens xs, x `mod` 2 /= 0 ] == []
+Prelude Test.QuickCheck> quickCheck test_evens
++++ OK, passed 100 tests.
+"""]]
+
+Here we define a test function that asserts that a list of even numbers
+shouldn't contain any odd ones. Passing this function to Quickcheck
+shows that the function passed 100 tests. Quickcheck sees that our
+`test_evens` function takes a list of numbers and returns a boolean, and
+it tests our code by generating a set of random inputs and executing it
+with those inputs.
+
+Clearly this type of testing can be very useful, and not just for
+Haskell programs. [Theft](https://github.com/silentbicycle/theft) is a C
+library that brings Quickcheck style testing to C. This sort of testing
+is known as [Property Testing][].
+
+Let's reimplement our Haskell code in C,
+
+[[!format c """
+#include <stdio.h>
+#include <stdlib.h>
+#include <theft.h>
+
+struct IntArray {
+    int len;
+    int arr[];
+};
+
+struct IntArray *evens(struct IntArray *input)
+{
+    int nevens = 0;
+    struct IntArray *output;
+
+    if (input == NULL) {
+        return NULL;
+    }
+
+    output = malloc(sizeof (struct IntArray) + input->len * sizeof(int));
+
+    if (output == NULL) {
+        return NULL;
+    }
+
+    for (int i = 0; i < input->len; i++) {
+        if (input->arr[i] % 2 == 0) {
+            output->arr[nevens++] = input->arr[i];
+        }
+    }
+
+    output->len = nevens;
+    return output;
+}
+"""]]
+
+Here we define a function that takes an array of integers and outputs an
+array of even integers.
+
+Now let's do some testing!
+
+Since C is not strongly typed like Haskell we need to define a function
+that describes what a test input should look like. Providing this
+information to Theft will allow it to generate real test input data. The
+function should have the following prototype,
+
+[[!format c """
+enum theft_alloc_res allocate_int_array(struct theft *, void *, void **)
+"""]]
+
+Let's write it!
+
+[[!format c """
+enum theft_alloc_res allocate_int_array(struct theft *t, void *data, void **result)
+{
+    int SIZE_LIMIT = 100;
+
+    int size = theft_random_choice(t, SIZE_LIMIT);
+
+    struct IntArray *numbers = malloc(sizeof (struct IntArray) + size * sizeof(int));
+
+    if (numbers == NULL) {
+        return THEFT_ALLOC_ERROR;
+    }
+
+    for (int i = 0; i < size; i++) {
+        numbers->arr[i] = theft_random_choice(t, INT_MAX);
+    }
+
+    numbers->len = size;
+
+    *result = numbers;
+
+    return THEFT_ALLOC_OK;
+}
+"""]]
+
+`theft_random_choice` is a function that will pick a random number
+between 0 and some defined limit. The result is not truly random, but
+instead based on the complexity of the input Theft requires. The
+documentation for Theft points out that the main thing with this is to
+ensure that wherever `theft_random_choice` returns 0 our
+`alloc_int_array` function should return the simplest input possible, in
+our case that would be an empty array.
+
+Theft passes a reference pointer to the `alloc_int_array` function, this
+must be updated to point to the array we have allocated before the
+function returns with `THEFT_ALLOC_OK`. In the event of some kind of
+error the function should return `THEFT_ALLOC_ERROR`
+
+Next we write the property function, this function takes an input
+array of integers generated by Theft, runs our `evens` function over that input and
+asserts that the resultant output doesn't contain any odd numbers.
+
+[[!format c """
+enum theft_trial_res property_array_of_evens_has_no_odd_numbers(struct theft *t, void *test_input)
+{
+    struct IntArray *test_array = test_input;
+
+    struct IntArray *result = evens(test_array);
+
+    // Array of even numbers should not contain any odd numbers
+    for (int i = 0; i < result->len; i++) {
+        if (result->arr[i] % 2 != 0) {
+            return THEFT_TRIAL_FAIL;
+        }
+    }
+
+    return THEFT_TRIAL_PASS;
+}
+"""]]
+
+Putting this together, we define some boiler plate to cover the various
+functions we just defined for generating test inputs,
+
+[[!format c """
+struct theft_type_info random_array_info = {
+    .alloc = allocate_int_array,
+    .free = theft_generic_free_cb,
+    .autoshrink_config = {
+        .enable = true,
+    }
+};
+"""]]
+
+The `alloc` member is updated to point to the function we just defined.
+Since the test inputs are dynamically allocated with `malloc` they will need
+to be freed later on. Theft provides a generic function for freeing
+which is sufficient for our purposes: `theft_generic_free_cb`.
+
+The last member of this structure needs more explanation. If Theft
+encounters an input which causes the test to fail, it will try to pare
+down the input to the smallest input that causes failure; this
+is called shrinking.
+
+Theft lets you define a function that can provide some control over the
+shrinking process, or it can use its own shrinking functions:
+autoshrinking. If autoshrinking is used however, the function that
+allocates test inputs must base the complexity of the input it generates
+upon the result of one of the `theft_random` functions, such as
+`theft_random_bits`, or `theft_random_choice`. This is why our
+`alloc_int_array` function uses `theft_random_choice` rather than
+standard pseudo random number generating functions.
+
+Finally we write a function to execute the tests,
+
+[[!format c """
+int main(void)
+{
+    theft_seed seed = theft_seed_of_time();
+    struct theft_run_config config = {
+        .name = __func__,
+        .prop1 = property_array_of_evens_has_no_odd_numbers,
+        .type_info = { &random_array_info },
+        .seed = seed
+    };
+

(Diff truncated)
publishing
diff --git a/posts/aoc-2017.mdwn b/posts/aoc-2017.mdwn
new file mode 100644
index 0000000..388e3e2
--- /dev/null
+++ b/posts/aoc-2017.mdwn
@@ -0,0 +1,39 @@
+[[!meta date="Wed, 29 Nov 2017 12:00:07 +0000"]]
+[[!meta title="Advent Of Code, 2017"]]
+[[!meta author="Daniel Silverstone"]]
+
+[Previously][] I mentioned the [Advent of Code][] as a possible thing you might
+want to look at for using as a way to learn a new language in a fun and
+exciting way during December.
+
+This year, it'll be running again, and I intend to have a go at it again in
+[Rust][] because I feel like I ought to continue my journey into that language.
+
+It's important to note, though, that I find it takes me between 30 and 90
+minutes **per day** to engage properly with the problems, and frankly the
+30 minute days are far more rare than the 90 minute ones.  As such, I urge
+you to not worry if you cannot allocate the time to take part every day.  Ditto
+if you start and then find you cannot continue, do not feel ashamed.  Very few
+Yakking readers are as lucky as I am in having enough time to myself to take
+part.
+
+However, if you can give up the time, and you do fancy it, then join in and if
+you want you can join my private leaderboard and not worry so much about
+competing with the super-fast super-clever people out there who are awake at
+midnight Eastern time (when the problems are published).  If you want to join
+the leaderboard (which contains some [Debian][] people, some [Codethink][]
+people, and hopefully by now, some Yakking people) then you will need (after
+joining the AoC site) to go to the private leaderboard section and enter the
+code: `69076-d4b54074`.  If you're really enthusiastic, and lucky enough to be
+able to afford it, then support AoC via their `AoC++` page with a few dollars
+too.
+
+Regardless of whether you join in with AoC or not, please remember to always
+take as much pleasure as you can in your coding opportunities, however they may
+present themselves.
+
+[Previously]: /posts/code-for-fun/
+[Advent of Code]: https://adventofcode.com/
+[Rust]: https://www.rust-lang.org/
+[Debian]: https://www.debian.org/
+[Codethink]: https://www.codethink.co.uk/

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

publishing
diff --git a/posts/use-early.mdwn b/posts/use-early.mdwn
new file mode 100644
index 0000000..258e205
--- /dev/null
+++ b/posts/use-early.mdwn
@@ -0,0 +1,55 @@
+[[!meta date="Wed, 22 Nov 2017 12:00:08 +0000"]]
+[[!meta title="Start using your new project early"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag new-project practices]]
+
+You've started a new project. When should you start using it "in
+anger", "for real", "in production"? My advice is to do so as early as you can.
+
+I did this for my newest project. I've been developing it slowly, and
+things had matured enough that it could now actually do things. I set
+up two instances doing things that I, and my company, now rely on. If
+the software breaks, I will need to take action (disable the broken
+instances, do things in another way until I fix the software).
+
+The point of doing this early is that it gives me quick feedback on
+whether the software works at all, and makes it easy to add new
+features, and makes it easier for others to try out the software.
+(When I announce it publically, which I'm not yet doing.)
+
+* I see quickly if something doesn't work. (For now, it does.)
+* I see at once if there's a missing feature that I urgently need. (I
+  have found two bugs yesterday.)
+* I see what is awkward and cumbersome for configuring, deploying the
+  software. (So many interacting components.)
+* I see if it's nice to actually use. (I need to find someone to write
+  a web interface, and need to improve the command line tool.)
+* I see if the performance is adequate and get an idea what the actual
+  resource requirements are. (Not many resources needed for now. Even
+  the cheapest VM I could choose is adequate.)
+* I get more confident in the software the more I actually use it.
+  Writing a test suite is good, but real use is better. Real use
+  always comes up with things you didn't think about writing tests
+  for.
+
+In order to set up not just one but two instances, I had to make the
+deployment automated. (I'm that lazy, and I don't apologise for
+that.)
+
+Thanks to an automated setup, when I add features or fix bugs,
+they're easy to roll out. It's now almost as easy as just running
+the program from the source tree.
+
+My development process is now, I write tests; I write code; tests
+pass; I tag a release; I let CI build it; and I run Ansible to upgrade
+everywhere. About 15 seconds of work once the tests pass, though it
+takes a couple of minutes of wall-clock time, since I run CI on my
+laptop.
+
+Apart from the benefits that come from the features of the
+software itself, getting to this stage is emotionally very rewarding. In
+one day, my little pet project went from "I like this idea" to "it's a
+thing".
+
+I recommend you start using your stuff in production earlier rather
+than later. Do it now, do it every day.

Fix formatting error
diff --git a/posts/data-processing-commands.mdwn b/posts/data-processing-commands.mdwn
index f1cd8e8..2481671 100644
--- a/posts/data-processing-commands.mdwn
+++ b/posts/data-processing-commands.mdwn
@@ -70,6 +70,7 @@ It is not possible to define a character *sequence* as a delimiter.
     Try `cut --help' for more information.
 
 For this more complicated tools need to be used.
+
     $ awk <testdata '{ split($0, A, /->/); print A[2] }'
     b
 

Added a comment: Re: cut example and uniq option
diff --git a/posts/data-processing-commands/comment_2_c49a7b99f7bda35247299f9b5bb72387._comment b/posts/data-processing-commands/comment_2_c49a7b99f7bda35247299f9b5bb72387._comment
new file mode 100644
index 0000000..aa47c6f
--- /dev/null
+++ b/posts/data-processing-commands/comment_2_c49a7b99f7bda35247299f9b5bb72387._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: cut example and uniq option"
+ date="2017-11-20T13:33:51Z"
+ content="""
+Thanks for your comment.
+
+Yes it's missing content because of a formatting error in the source (there should be an empty line before the code block).
+The output that it was supposed to have is:
+
+    $ awk <testdata '{ split($0, A, /->/); print A[2] }'
+    b
+
+I'll get it fixed.
+"""]]

Added a comment: cut example and uniq option
diff --git a/posts/data-processing-commands/comment_1_b2c5598f34dc5a804fda1e17c108e98e._comment b/posts/data-processing-commands/comment_1_b2c5598f34dc5a804fda1e17c108e98e._comment
new file mode 100644
index 0000000..02422dc
--- /dev/null
+++ b/posts/data-processing-commands/comment_1_b2c5598f34dc5a804fda1e17c108e98e._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="riccio@2156bd061582af8c0a76482b0dc0ff28dea95cbb"
+ nickname="riccio"
+ avatar="http://cdn.libravatar.org/avatar/54e73b2de2c0c3dbe275f0621c7bfebb"
+ subject="cut example and uniq option"
+ date="2017-11-18T10:58:40Z"
+ content="""
+Hi, thanks for this great blog!
+
+Regarding the cut example: the last line says \"For this more complicated tools need to be used. $ awk /); print A[2] }' b\", I think something is missing.
+Regarding the sort/uniq paragraph: the option I find more useful of uniq is \"-c\" for counting occourrences.
+
+Thank you again,
+Riccardo
+"""]]

publishing
diff --git a/posts/blank.mdwn b/posts/blank.mdwn
new file mode 100644
index 0000000..e8af375
--- /dev/null
+++ b/posts/blank.mdwn
@@ -0,0 +1,19 @@
+[[!meta date="Wed, 15 Nov 2017 12:33:18 +0000"]]
+[[!meta title="This post intentionally left blank"]]
+[[!meta author="Lars Wirzenius"]]
+
+This post intentionally left
+[blank](https://en.wikipedia.org/wiki/Intentionally_blank_page).
+
+We ran out of Yakking articles and energy to write new ones. There's
+plenty of things to write about, but the usual Yakking writers have
+been feeling a bit under the weather lately. If you'd like to help,
+leave a comment on Yakking, or join the IRC channel `#yakking` (on the
+irc.oftc.net network), and offer an article.
+
+The previous break in the weekly schedule was December 25, 2013. That
+was due to a typo in the intended publication date: it got scheduled
+for 2103-12-25, not 2013-12-25.
+
+We hope to return back to the normal schedule. Your patience is
+appreciated. Resistance less than 4.2 Ohm is futile.

publishing
diff --git a/posts/time-cputime.mdwn b/posts/time-cputime.mdwn
new file mode 100644
index 0000000..d2189dc
--- /dev/null
+++ b/posts/time-cputime.mdwn
@@ -0,0 +1,275 @@
+[[!meta date="Wed, 08 Nov 2017 14:30:19 +0000"]]
+[[!meta title="What is Time - CPU time"]]
+[[!meta author="Richard Maw"]]
+[[!tag time]]
+
+Before everyone had a multitude of computers of their own
+computers were rare,
+and if you wanted to use one you had to share it.
+
+Given the demand for computers exceeded the supply,
+people had to share time using it.
+
+Initially you could do this with a stop watch,
+but it's better for the computer itself to be able to measure this time
+since as computers became more complicated:
+
+1.  Pre-emption, where one process can be interrupted to run another,
+    means the time take up by a program
+    isn't just the difference between when the program started and ended.
+
+2.  Multi-threading, where a program can run multiple commands simultaneously,
+    means you can use CPU time at a rate of more than one CPU second per second.
+
+Computers became so pervasive that most computer users don't need to share,
+but virtual server providers also need to account for time used,
+and CPU time can also be used to measure how long it takes to perform an
+operation for [profiling][] purposes
+so when a program is slow you know which
+part is the most worth your time to [optimise][optimization].
+
+[profiling]: https://en.wikipedia.org/wiki/Profiling_(computer_programming)
+[optimization]: https://en.wikipedia.org/wiki/Program_optimization
+
+Getting CPU time
+----------------
+
+The CPU time is read in the same way as other clocks,
+with different clock IDs for each process or thread.
+
+1.  Current process with `CLOCK_PROCESS_CPUTIME_ID`.
+
+        int ret = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time);
+
+2.  Current thread with `CLOCK_THREAD_CPUTIME_ID`.
+
+        int ret = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time);
+
+3.  Another process with [clock_getcpuclockid(3)][].
+
+        int pid_gettime(pid_t pid, struct timespec *tp) {
+            int ret;
+            clockid_t clockid;
+            ret = clock_getcpuclockid(pid, &clockid);
+            if (ret != 0) {
+                return ret;
+            }
+            ret = clock_gettime(clockid, tp);
+            return ret;
+        }
+
+4.  Another thread with [pthread_getcpuclockid(3)][].
+
+        int thread_gettime(pthread_t thread, struct timespec *tp) {
+            int ret;
+            clockid_t clockid;
+            ret = pthread_getcpuclockid(thread, &clockid);
+            if (ret != 0) {
+                return ret;
+            }
+            ret = clock_gettime(clockid, tp);
+            return ret;
+        }
+
+See [[gettime.c|gettime.c]] for an example program for reading the times,
+and [[Makefile|Makefile]] for build instructions.
+
+[clock_getcpuclockid(3)]: http://man7.org/linux/man-pages/man3/clock_getcpuclockid.3.html
+[pthread_getcpuclockid(3)]: http://man7.org/linux/man-pages/man3/pthread_getcpuclockid.3.html
+
+Profiling
+---------
+
+We can instrument code (see [[profile-unthreaded.c]])
+to see how much time a section takes to run.
+
+[[!format C """
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+
+static void print_time(FILE *f, struct timespec time) {
+	fprintf(f, "%lld.%09lld\n", (long long)time.tv_sec, (long long)time.tv_nsec);
+}
+
+int main(int argc, char **argv) {
+	enum {
+		ITERATIONS = 1000000,
+	};
+	int ret, exit = 0;
+	struct timespec start, end;
+
+	ret = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
+	if (ret != 0) {
+		perror("clock_gettime");
+		exit = 1;
+		goto exit;
+	}
+
+	for (int i = 0; i < ITERATIONS; i++) {
+		fprintf(stdout, "% 7d\n", i);
+	}
+
+	ret = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
+	if (ret != 0) {
+		perror("clock_gettime");
+		exit = 1;
+		goto exit;
+	}
+
+	end.tv_sec -= start.tv_sec;
+	end.tv_nsec -= start.tv_nsec;
+	if (end.tv_nsec < 0) {
+		end.tv_sec--;
+		end.tv_sec += 1000000000l;
+	}
+
+	print_time(stderr, end);
+
+exit:
+	return exit;
+}
+"""]]
+
+[[!format sh """
+$ make profile-unthreaded
+$ ./profile-unthreaded >/tmp/f
+0.073965395
+"""]]
+
+We can make use of threads to try to speed this up (see [[profile-threaded.c]]).
+
+[[!format C """
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+#include <unistd.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
+
+static void print_time(FILE *f, struct timespec time) {
+	fprintf(f, "%lld.%09lld\n", (long long)time.tv_sec, (long long)time.tv_nsec);
+}
+
+struct thread_args {
+	int fd;
+	int start;
+	unsigned len;
+};
+
+void *thread_run(void *_thread_args) {
+	struct thread_args *thread_args = _thread_args;
+	char buf[9];
+	for (int i = thread_args->start;
+	     i < thread_args->start + thread_args->len; i++) {
+		ssize_t len = snprintf(buf, ARRAY_SIZE(buf), "% 7d\n", i);
+		pwrite(thread_args->fd, buf, len, i * len);
+	}
+	return NULL;
+}
+
+int main(int argc, char **argv) {
+	enum {
+		ITERATIONS = 1000000,
+		THREADS = 4,
+	};
+	int i, ret, exit = 0;
+	struct timespec start, end;
+	pthread_t threads[THREADS];
+	struct thread_args thread_args[THREADS];
+
+	ret = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
+	if (ret != 0) {
+		perror("clock_gettime");
+		exit = 1;
+		goto exit;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(threads); i++) {
+		thread_args[i].fd = 1;
+		thread_args[i].start = ITERATIONS / THREADS * i;

(Diff truncated)
Added a comment: Thanks
diff --git a/posts/communicating/comment_2_40837523a5245cf6d0387c8d27023161._comment b/posts/communicating/comment_2_40837523a5245cf6d0387c8d27023161._comment
new file mode 100644
index 0000000..9595984
--- /dev/null
+++ b/posts/communicating/comment_2_40837523a5245cf6d0387c8d27023161._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://liw.fi/"
+ avatar="http://cdn.libravatar.org/avatar/c9632d33d21a2acc25cd320c2dcbce25cb21ad42117dc19426c51ce1cdf042dc"
+ subject="Thanks"
+ date="2017-11-01T12:40:04Z"
+ content="""
+You're right, that would've been a better word choice. Thanks.
+"""]]

Added a comment: I know what you mean, but...
diff --git a/posts/communicating/comment_1_6ff904af66801b8e47b31866587c0ea0._comment b/posts/communicating/comment_1_6ff904af66801b8e47b31866587c0ea0._comment
new file mode 100644
index 0000000..d8232c1
--- /dev/null
+++ b/posts/communicating/comment_1_6ff904af66801b8e47b31866587c0ea0._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="lesley.g.mitchell@c6f89a60a1c23d0b27e6f1fddd7b4cd9c655ea16"
+ nickname="lesley.g.mitchell"
+ avatar="http://cdn.libravatar.org/avatar/969c5042049a7b48fcebf8020edb503a"
+ subject="I know what you mean, but..."
+ date="2017-11-01T12:22:00Z"
+ content="""
+Might I suggest rather than \"short\", you really mean that communication should be kept \"brief\" or \"concise\".
+"""]]

publishing
diff --git a/posts/communicating.mdwn b/posts/communicating.mdwn
new file mode 100644
index 0000000..817ddd4
--- /dev/null
+++ b/posts/communicating.mdwn
@@ -0,0 +1,39 @@
+[[!meta date="Wed, 01 Nov 2017 12:00:10 +0000"]]
+[[!meta title="Communicating"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag communication]]
+
+Most of software development is, in fact, communication. Even more so
+for free software projects that involve more than one person.
+Communication is an overhead, something you need to do on top of
+coding, so many hackers don't pay much attention to it. This is a
+mistake. A project whose members communicate effective gets more done
+in less time than one whose members don't. Here are some hints that
+may be useful:
+
+* use the appropriate _medium_: if you need an answer soon, ask on a
+  chat system such as IRC; if you can wait a while, use email or a
+  blog post or a web forum
+
+* be short and clear: a long, rambling question takes more time and
+  effort to read, never mind respond to, and is often less clear and
+  thus results in a less helpful answer
+
+* take responsibility of getting the problem solved: develop a way to
+  reproduce the problem, and if it's code, with the shortest, simplest
+  piece of self-standing code you can (you'll often find you find the
+  answer yourself)
+
+* make it easy to help you:
+  [explain what you really want to achieve](http://xyproblem.info/)
+  (not something else, even if you think it's easier), and what you've
+  done, and what the exact result is (use copy-paste or take a
+  screenshot)
+
+* don't be insulting, arrogant, dismissive, or aggressive: you need
+  help, don't make those you want it from not like you, or they might
+  not even try
+
+* say thank you: you'll be remembered well, and those who helped you
+  (or tried to) will have more fun and are more motivated to work for
+  free for others in the future

removed
diff --git a/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment b/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
deleted file mode 100644
index ee5c2e6..0000000
--- a/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
+++ /dev/null
@@ -1,12 +0,0 @@
-[[!comment format=mdwn
- username="richardipsum"
- avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
- subject="comment 1"
- date="2017-10-25T12:28:14Z"
- content="""
-Related to the issue of ethics in software is the ability of some companies to e.g. [swing an election].
-I'd argue that Google and Facebook can be considered ethically problematic in this respect.
-That's not to say that these companies are doing any of this intentionally ofcourse.
-
-[swing an election]: http://dci.mit.edu/assets/papers/decentralized_web.pdf
-"""]]

Revert "removed"
This reverts commit 55fb07c53f4174f837c0f14b404bea563690f977.
diff --git a/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment b/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment
new file mode 100644
index 0000000..d08cf96
--- /dev/null
+++ b/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="fa-ml@8b7c0cd18f4588039684c9065d74e687ce921e47"
+ nickname="fa-ml"
+ avatar="http://cdn.libravatar.org/avatar/9784765515033db9c353525245a41ceb"
+ subject="comment 2"
+ date="2017-10-25T13:15:15Z"
+ content="""
+> \"Does it promote $BADTHINGS, directly or indirectly?\"
+
+Slippery surface, as one can easily put GPG/TOR/GNUNet (and loosely following your example, R) in that $BADTHINGS basket.  
+A medical professional cures people regardless, a lawyer defends their client regardless: is a Free Software contributor more equipped to indulge in this deontological Pandora's box?
+"""]]

Revert "removed"
This reverts commit d78914d20de7dd384f0c41a4bd053ffa8e243fd4.
diff --git a/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment b/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment
new file mode 100644
index 0000000..c4f9a75
--- /dev/null
+++ b/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="lesley.g.mitchell@c6f89a60a1c23d0b27e6f1fddd7b4cd9c655ea16"
+ nickname="lesley.g.mitchell"
+ avatar="http://cdn.libravatar.org/avatar/969c5042049a7b48fcebf8020edb503a"
+ subject="Further reading on the topic"
+ date="2017-10-26T12:43:51Z"
+ content="""
+Computer/Programming/Information Ethics is a whole discipline in itself, though it is certainly a topic that every programmer really ought have some grounding in.
+
+The Wikipedia page on the topic - <https://en.wikipedia.org/wiki/Programming_ethics> - is a good place to start for more general information and some ideas about what to consider.
+
+For a more philosophical exploration of the topic, the Stanford Encyclopedia of Philosophy has some good articles, such as: <https://plato.stanford.edu/entries/ethics-computer/> and <https://plato.stanford.edu/entries/computing-responsibility/>
+
+There are also a whole range of books on the topic both from computing perspectives and more philosophical ones.
+
+The Open University also offers a free course on the subject, [Introducing Ethics in Information and Computer Sciences](http://www.open.edu/openlearn/education/educational-technology-and-practice/educational-technology/introducing-ethics-information-and-computer-sciences/content-section-0?active-tab=description-tab)
+"""]]

Revert "removed"
This reverts commit e150ad3cb96ca207e9fa93cd38ba47506e528975.
diff --git a/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment b/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
new file mode 100644
index 0000000..ee5c2e6
--- /dev/null
+++ b/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="richardipsum"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="comment 1"
+ date="2017-10-25T12:28:14Z"
+ content="""
+Related to the issue of ethics in software is the ability of some companies to e.g. [swing an election].
+I'd argue that Google and Facebook can be considered ethically problematic in this respect.
+That's not to say that these companies are doing any of this intentionally ofcourse.
+
+[swing an election]: http://dci.mit.edu/assets/papers/decentralized_web.pdf
+"""]]

removed
diff --git a/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment b/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment
deleted file mode 100644
index d08cf96..0000000
--- a/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment
+++ /dev/null
@@ -1,12 +0,0 @@
-[[!comment format=mdwn
- username="fa-ml@8b7c0cd18f4588039684c9065d74e687ce921e47"
- nickname="fa-ml"
- avatar="http://cdn.libravatar.org/avatar/9784765515033db9c353525245a41ceb"
- subject="comment 2"
- date="2017-10-25T13:15:15Z"
- content="""
-> \"Does it promote $BADTHINGS, directly or indirectly?\"
-
-Slippery surface, as one can easily put GPG/TOR/GNUNet (and loosely following your example, R) in that $BADTHINGS basket.  
-A medical professional cures people regardless, a lawyer defends their client regardless: is a Free Software contributor more equipped to indulge in this deontological Pandora's box?
-"""]]

removed
diff --git a/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment b/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment
deleted file mode 100644
index c4f9a75..0000000
--- a/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment
+++ /dev/null
@@ -1,17 +0,0 @@
-[[!comment format=mdwn
- username="lesley.g.mitchell@c6f89a60a1c23d0b27e6f1fddd7b4cd9c655ea16"
- nickname="lesley.g.mitchell"
- avatar="http://cdn.libravatar.org/avatar/969c5042049a7b48fcebf8020edb503a"
- subject="Further reading on the topic"
- date="2017-10-26T12:43:51Z"
- content="""
-Computer/Programming/Information Ethics is a whole discipline in itself, though it is certainly a topic that every programmer really ought have some grounding in.
-
-The Wikipedia page on the topic - <https://en.wikipedia.org/wiki/Programming_ethics> - is a good place to start for more general information and some ideas about what to consider.
-
-For a more philosophical exploration of the topic, the Stanford Encyclopedia of Philosophy has some good articles, such as: <https://plato.stanford.edu/entries/ethics-computer/> and <https://plato.stanford.edu/entries/computing-responsibility/>
-
-There are also a whole range of books on the topic both from computing perspectives and more philosophical ones.
-
-The Open University also offers a free course on the subject, [Introducing Ethics in Information and Computer Sciences](http://www.open.edu/openlearn/education/educational-technology-and-practice/educational-technology/introducing-ethics-information-and-computer-sciences/content-section-0?active-tab=description-tab)
-"""]]

removed
diff --git a/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment b/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
deleted file mode 100644
index ee5c2e6..0000000
--- a/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
+++ /dev/null
@@ -1,12 +0,0 @@
-[[!comment format=mdwn
- username="richardipsum"
- avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
- subject="comment 1"
- date="2017-10-25T12:28:14Z"
- content="""
-Related to the issue of ethics in software is the ability of some companies to e.g. [swing an election].
-I'd argue that Google and Facebook can be considered ethically problematic in this respect.
-That's not to say that these companies are doing any of this intentionally ofcourse.
-
-[swing an election]: http://dci.mit.edu/assets/papers/decentralized_web.pdf
-"""]]

Added a comment: Further reading on the topic
diff --git a/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment b/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment
new file mode 100644
index 0000000..c4f9a75
--- /dev/null
+++ b/posts/ethics/comment_3_89c290cc731c2966a94051d1e44d619c._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="lesley.g.mitchell@c6f89a60a1c23d0b27e6f1fddd7b4cd9c655ea16"
+ nickname="lesley.g.mitchell"
+ avatar="http://cdn.libravatar.org/avatar/969c5042049a7b48fcebf8020edb503a"
+ subject="Further reading on the topic"
+ date="2017-10-26T12:43:51Z"
+ content="""
+Computer/Programming/Information Ethics is a whole discipline in itself, though it is certainly a topic that every programmer really ought have some grounding in.
+
+The Wikipedia page on the topic - <https://en.wikipedia.org/wiki/Programming_ethics> - is a good place to start for more general information and some ideas about what to consider.
+
+For a more philosophical exploration of the topic, the Stanford Encyclopedia of Philosophy has some good articles, such as: <https://plato.stanford.edu/entries/ethics-computer/> and <https://plato.stanford.edu/entries/computing-responsibility/>
+
+There are also a whole range of books on the topic both from computing perspectives and more philosophical ones.
+
+The Open University also offers a free course on the subject, [Introducing Ethics in Information and Computer Sciences](http://www.open.edu/openlearn/education/educational-technology-and-practice/educational-technology/introducing-ethics-information-and-computer-sciences/content-section-0?active-tab=description-tab)
+"""]]

Added a comment: comment 2
diff --git a/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment b/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment
new file mode 100644
index 0000000..d08cf96
--- /dev/null
+++ b/posts/ethics/comment_2_b52385572b8ee0edb495bc13186c544e._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="fa-ml@8b7c0cd18f4588039684c9065d74e687ce921e47"
+ nickname="fa-ml"
+ avatar="http://cdn.libravatar.org/avatar/9784765515033db9c353525245a41ceb"
+ subject="comment 2"
+ date="2017-10-25T13:15:15Z"
+ content="""
+> \"Does it promote $BADTHINGS, directly or indirectly?\"
+
+Slippery surface, as one can easily put GPG/TOR/GNUNet (and loosely following your example, R) in that $BADTHINGS basket.  
+A medical professional cures people regardless, a lawyer defends their client regardless: is a Free Software contributor more equipped to indulge in this deontological Pandora's box?
+"""]]

Added a comment
diff --git a/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment b/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
new file mode 100644
index 0000000..ee5c2e6
--- /dev/null
+++ b/posts/ethics/comment_1_286d1434399328d4e17422d38838f063._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="richardipsum"
+ avatar="http://cdn.libravatar.org/avatar/48cd8810cb554be5891de36dd031b49c"
+ subject="comment 1"
+ date="2017-10-25T12:28:14Z"
+ content="""
+Related to the issue of ethics in software is the ability of some companies to e.g. [swing an election].
+I'd argue that Google and Facebook can be considered ethically problematic in this respect.
+That's not to say that these companies are doing any of this intentionally ofcourse.
+
+[swing an election]: http://dci.mit.edu/assets/papers/decentralized_web.pdf
+"""]]

publishing
diff --git a/posts/ethics.mdwn b/posts/ethics.mdwn
new file mode 100644
index 0000000..4238a5a
--- /dev/null
+++ b/posts/ethics.mdwn
@@ -0,0 +1,38 @@
+[[!meta date="Wed, 25 Oct 2017 12:00:12 +0000"]]
+[[!meta title="Ethics in software development"]]
+[[!meta author="Lars Wirzenius"]]
+
+Free software development always has an ethical dimension. We develop
+free software instead of proprietary software to allow people, the
+users of our software, to not be as controlled by vendors of
+proprietary software as they might otherwise be.
+
+Software freedom is, however, only one ethical dimension. Free
+software can also be unethical, for example by doing things that hurt
+people. As an extreme example, a free software implementation of
+ransomware would be quite problematic, under any licence. It doesn't
+matter if the program is, say, under the GPL licence, if it attacks
+people's computers, and encrypts their data and refuses to decrypt it
+until the author of the program has paid a ransom. Not even if the
+program installs its own source code on the computer when it encrypts
+all other data would it be considered ethical.
+
+When you write software you should consider the ethics, the morality,
+and the impact on everyone. For example:
+
+* Does it promote racism, sexism, or violence, directly or indirectly?
+  For example, if it's an "AI" that tries to guess if someone will
+  commit a crime in the future, is it effectively only based their race?
+
+* Does it use bandwidth unneccessarily? Bandwidth is an expensive
+  luxury in some parts of the worlds, so wasting it discrimnates
+  against people in those parts of the world.
+
+* Does it "call home", such as report usage to the developers? This
+  violates user privacy. Gathering usage statistics can be very useful
+  to the developers in more ways than one, but to do so without requesting
+  permission remains a violation of privacy.
+
+Have you encountered ethically problematic software?
+Or perhaps have you found some exemplar of ethical software development?
+Why not give an example in the comments below...

Added a comment: Re: time_t could be longer than long
diff --git a/posts/time-rendering/comment_2_d43074875f8870161365a06c96bc99aa._comment b/posts/time-rendering/comment_2_d43074875f8870161365a06c96bc99aa._comment
new file mode 100644
index 0000000..ee27150
--- /dev/null
+++ b/posts/time-rendering/comment_2_d43074875f8870161365a06c96bc99aa._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="http://richard.maw.name/"
+ nickname="Richard Maw"
+ avatar="http://cdn.libravatar.org/avatar/4d312a0989b085a9dfa9ba61d60da130979b9c408659132fea11d5efe2c90fc5"
+ subject="Re: time_t could be longer than long"
+ date="2017-10-21T16:11:41Z"
+ content="""
+Thanks Ben. I've made that change.
+
+I unfortunately wrote this article before I discussed this issue at DebConf.
+"""]]

Convert "long" format strings to "long long" for printing time
diff --git a/posts/time-rendering.mdwn b/posts/time-rendering.mdwn
index 1e649c0..e09e7c0 100644
--- a/posts/time-rendering.mdwn
+++ b/posts/time-rendering.mdwn
@@ -52,11 +52,11 @@ struct timespec {
 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.
+with the `%09lld` [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);
+printf("%lld.%09lld\n", (long long)time.tv_sec, (long long)time.tv_nsec);
 """]]
 
 `struct tm`
@@ -218,7 +218,7 @@ int main(void) {
 	}
 
 	/* Render the current time as the formatted time plus nanoseconds. */
-	printf("%s.%09ld\n", tbuf, (long)time.tv_nsec);
+	printf("%s.%09lld\n", tbuf, (long long)time.tv_nsec);
 
 cleanup:
 	free(tbuf);
diff --git a/posts/time-rendering/time.c b/posts/time-rendering/time.c
index aad7708..2ce46bc 100644
--- a/posts/time-rendering/time.c
+++ b/posts/time-rendering/time.c
@@ -99,7 +99,7 @@ int main(void) {
 	}
 
 	/* Render the current time as the formatted time plus nanoseconds. */
-	printf("%s.%09ld\n", tbuf, (long)time.tv_nsec);
+	printf("%s.%09lld\n", tbuf, (long long)time.tv_nsec);
 
 cleanup:
 	free(tbuf);

Added a comment: Leap seconds can still cause disruption
diff --git a/posts/time-leapseconds/comment_1_54a7898faf1efdd14e80e695e397928e._comment b/posts/time-leapseconds/comment_1_54a7898faf1efdd14e80e695e397928e._comment
new file mode 100644
index 0000000..fea58e2
--- /dev/null
+++ b/posts/time-leapseconds/comment_1_54a7898faf1efdd14e80e695e397928e._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="ben@1bd5a357d246e09ae8a003093163aabb0190beb6"
+ nickname="ben"
+ avatar="http://cdn.libravatar.org/avatar/344b20b16cdf7607bfca3d9b130a5876"
+ subject="Leap seconds can still cause disruption"
+ date="2017-10-20T14:35:46Z"
+ content="""
+Leap seconds are inserted at 23:59:60 UTC, not local time. Some stock exchanges shut down briefly in the middle of 2015 rather than keep running across the leap second at the risk of timekeeping errors.
+"""]]

Added a comment: time_t could be longer than long
diff --git a/posts/time-rendering/comment_1_78794363393ce28fae3ea05952550499._comment b/posts/time-rendering/comment_1_78794363393ce28fae3ea05952550499._comment
new file mode 100644
index 0000000..7c3ffb0
--- /dev/null
+++ b/posts/time-rendering/comment_1_78794363393ce28fae3ea05952550499._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="ben@1bd5a357d246e09ae8a003093163aabb0190beb6"
+ nickname="ben"
+ avatar="http://cdn.libravatar.org/avatar/344b20b16cdf7607bfca3d9b130a5876"
+ subject="time_t could be longer than long"
+ date="2017-10-20T14:26:47Z"
+ content="""
+There are likely to be 32-bit systems still running in 2038, and in order to make that happen they will likely have a 64-bit time_t and 32-bit long. So please could you make your first example cast from time_t to long long, not long?
+"""]]

publishing
diff --git a/posts/keeping-passwords-safe.mdwn b/posts/keeping-passwords-safe.mdwn
new file mode 100644
index 0000000..5122c4a
--- /dev/null
+++ b/posts/keeping-passwords-safe.mdwn
@@ -0,0 +1,48 @@
+[[!meta date="Wed, 18 Oct 2017 12:00:15 +0000"]]
+[[!meta title="Keeping your passwords safe"]]
+[[!meta author="Daniel Silverstone"]]
+
+There're a number of ways of keeping your passwords as safe as can be.  One
+very old-school way is to write each password down in a book, and keep that
+book physically secure.  On the assumption that you can't remember the
+passwords without the book, this is a reasonable way to improve your security.
+Sadly it doesn't scale well and can make it quite hard to keep things
+up-to-date.
+
+More usefully, in today's multi-computer and multi-device world, there are
+programs called 'password managers' and as with anything even vaguely
+interesting there are a number of them to choose from.  Some names you may
+already be familiar with include [Keepassx][], [1Password][], and [LastPass][].
+
+Password managers offer you a way to effectively protect all your passwords
+with a single token, often allowing you to sync and manage your passwords
+without needing lots of knowledge of how things work.  They're usually also
+integrated with your web browser, your phone, etc, to allow you a seamless
+experience.
+
+If you're a little more paranoid than the normal geek though, and you're
+prepared to sacrifice a bit of simplicity for a bit more ease-of-mind, then you
+could try [Password Store][] (`pass`) which is written in [Bash][] and uses
+[GnuPG][].  I personally use `pass` and have my GnuPG key stored in a
+[Yubikey][] which I keep around my neck.  (There's also the [Gnuk][] which can,
+I believe, do a similar job) With the need of the physical token
+and also the PIN to unlock it, this is a [multifactor authentication][] system
+which I then can use to secure my passwords etc.  I then have it backed onto
+my own Git server where I can keep an eye on the content safely.
+
+I strongly suggest that if you're not using a password safe of some kind, that
+you get one set up and start using it.  In fact, if you've not got one, go and
+do it now and I'll see you next time...
+
+(Oh yeah, and if you look at multifactor authentication, be aware that your
+intrinsic factor today is simply your adversary's posession factor tomorrow)
+
+[Keepassx]: https://www.keepassx.org/
+[1Password]: https://1password.com/
+[LastPass]: https://www.lastpass.com/
+[Password Store]: https://www.passwordstore.org/
+[Bash]: https://www.gnu.org/software/bash/
+[GnuPG]: https://gnupg.org/
+[Yubikey]: https://www.yubico.com/start/
+[Gnuk]: https://www.fsij.org/category/gnuk.html
+[multifactor authentication]: https://en.wikipedia.org/wiki/Multi-factor_authentication

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]]