Recent changes to this wiki:

Correct spelling of Montréal
diff --git a/2017/flatpak_and_debian.mdwn b/2017/flatpak_and_debian.mdwn
index 55c03a3..12bdef2 100644
--- a/2017/flatpak_and_debian.mdwn
+++ b/2017/flatpak_and_debian.mdwn
@@ -8,7 +8,7 @@
 alt="Decorative photo of the indoor garden"
 caption="The indoor garden at Collège de Maisonneuve, the DebConf 17 venue"]]
 
-I'm currently at DebConf 17 in Montreal, back at DebConf for the first
+I'm currently at DebConf 17 in Montréal, back at DebConf for the first
 time in 10 years (last time was DebConf 7 in Edinburgh). It's great to
 put names to faces and meet more of my co-developers in person!
 

Update blog post with video and updated slides URL
diff --git a/2017/flatpak_and_debian.mdwn b/2017/flatpak_and_debian.mdwn
index e2fc4ca..55c03a3 100644
--- a/2017/flatpak_and_debian.mdwn
+++ b/2017/flatpak_and_debian.mdwn
@@ -1,6 +1,6 @@
 [[!meta title="DebConf 17: Flatpak and Debian"]]
 [[!meta date="2017-08-09 13:06:00 -04:00"]]
-[[!meta updated="2017-08-09 13:06:00 -04:00"]]
+[[!meta updated="2017-08-16 21:50:00 +01:00"]]
 [[!meta copyright="Copyright © 2017 Simon McVittie"]]
 [[!tag debian flatpak]]
 
@@ -12,17 +12,20 @@ I'm currently at DebConf 17 in Montreal, back at DebConf for the first
 time in 10 years (last time was DebConf 7 in Edinburgh). It's great to
 put names to faces and meet more of my co-developers in person!
 
-On Monday I gave a talk entitled “A Debian maintainer's guide to
-Flatpak”, aiming to introduce Debian developers to Flatpak, and show
+On Monday I gave a talk entitled “[A Debian maintainer's guide to
+Flatpak](https://debconf17.debconf.org/talks/59/)”, aiming to introduce
+Debian developers to Flatpak, and show
 how Flatpak and Debian (and Debian derivatives like SteamOS) can help
 each other. It seems to have been quite well received, with people
 generally positive about the idea of using Flatpak to deliver backports
 and faster-moving leaf packages (games!) onto the stable base platform
 that Debian is so good at providing.
 
-I've now put up my slides in the DebConf `git-annex` repository, with
+[A video of the talk](http://meetings-archive.debian.net/pub/debian-meetings/2017/debconf17/a-debian-maintainer-s-guide-to-flatpak.vp8.webm) is available from the Debian
+Meetings Archive.
+I've also put up my slides in the DebConf `git-annex` repository, with
 some small edits to link to more source code:
-[A Debian maintainer's guide to Flatpak](https://annex.debconf.org/debconf-share/debconf17/slides/debconf17_smcv_flatpak.html).
+[A Debian maintainer's guide to Flatpak](https://annex.debconf.org/debconf-share/debconf17/slides/59-debian-maintainers-guide-to-flatpak.html).
 [Source code for the slides](https://git.collabora.com/cgit/user/smcv/dc17.git/)
 is also available from Collabora's git server.
 
@@ -47,4 +50,7 @@ derivatives, with a lot of flexibility during development but very limited
 state on deployed systems, and Endless' approach seems a perfect fit for
 those situations.
 
+\[Edited 2017-08-16 to fix the link for the slides, and add links for the
+video\]
+
 [[!meta license="[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)"]]

Blog about DebConf and my talk
diff --git a/2017/flatpak_and_debian.mdwn b/2017/flatpak_and_debian.mdwn
new file mode 100644
index 0000000..e2fc4ca
--- /dev/null
+++ b/2017/flatpak_and_debian.mdwn
@@ -0,0 +1,50 @@
+[[!meta title="DebConf 17: Flatpak and Debian"]]
+[[!meta date="2017-08-09 13:06:00 -04:00"]]
+[[!meta updated="2017-08-09 13:06:00 -04:00"]]
+[[!meta copyright="Copyright © 2017 Simon McVittie"]]
+[[!tag debian flatpak]]
+
+[[!img indoor-garden.jpg align=right
+alt="Decorative photo of the indoor garden"
+caption="The indoor garden at Collège de Maisonneuve, the DebConf 17 venue"]]
+
+I'm currently at DebConf 17 in Montreal, back at DebConf for the first
+time in 10 years (last time was DebConf 7 in Edinburgh). It's great to
+put names to faces and meet more of my co-developers in person!
+
+On Monday I gave a talk entitled “A Debian maintainer's guide to
+Flatpak”, aiming to introduce Debian developers to Flatpak, and show
+how Flatpak and Debian (and Debian derivatives like SteamOS) can help
+each other. It seems to have been quite well received, with people
+generally positive about the idea of using Flatpak to deliver backports
+and faster-moving leaf packages (games!) onto the stable base platform
+that Debian is so good at providing.
+
+I've now put up my slides in the DebConf `git-annex` repository, with
+some small edits to link to more source code:
+[A Debian maintainer's guide to Flatpak](https://annex.debconf.org/debconf-share/debconf17/slides/debconf17_smcv_flatpak.html).
+[Source code for the slides](https://git.collabora.com/cgit/user/smcv/dc17.git/)
+is also available from Collabora's git server.
+
+The next step is to take my proof-of-concept for building
+Flatpak runtimes and apps from Debian and SteamOS packages,
+[flatdeb](https://git.collabora.com/cgit/user/smcv/flatdeb.git/), get it
+a bit more production-ready, and perhaps start publishing some sample
+runtimes from a cron job on a Debian or Collabora server. (By the way,
+if you downloaded that source right after my talk, please update - I've
+now pushed some late changes that were necessary to fix the 3D drivers
+for my OpenArena demo.)
+
+I don't think Debian will be going quite as far as
+[Endless](https://endlessos.com/) any time soon: as
+Cosimo outlined in the talk right before mine, they
+deploy their Debian derivative as an immutable base OS with
+[libOSTree](https://ostree.readthedocs.io/en/latest/), with all the
+user-installable modules above that coming from Flatpak. That model is
+certainly an interesting thing to think about for Debian derivatives,
+though: at Collabora we work on a lot of appliance-like embedded Debian
+derivatives, with a lot of flexibility during development but very limited
+state on deployed systems, and Endless' approach seems a perfect fit for
+those situations.
+
+[[!meta license="[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)"]]
diff --git a/2017/flatpak_and_debian/indoor-garden.jpg b/2017/flatpak_and_debian/indoor-garden.jpg
new file mode 100644
index 0000000..aaf9bdf
Binary files /dev/null and b/2017/flatpak_and_debian/indoor-garden.jpg differ

Blog about the GTK hackfest
diff --git a/2017/dbus_and_containers.mdwn b/2017/dbus_and_containers.mdwn
new file mode 100644
index 0000000..16195fd
--- /dev/null
+++ b/2017/dbus_and_containers.mdwn
@@ -0,0 +1,360 @@
+[[!meta title="GTK hackfest 2017: D-Bus communication with containers"]]
+[[!meta date="2017-03-23 18:07 +0000"]]
+[[!meta updated="2017-03-23 18:07 +0000"]]
+[[!meta copyright="Copyright © 2017 Simon McVittie"]]
+[[!tag debian gtk flatpak d-bus]]
+
+At the [GTK hackfest][] in London (which accidentally became mostly a
+Flatpak hackfest) I've mainly been looking into how to make D-Bus
+work better for app container technologies like [Flatpak][] and [Snap][].
+
+The initial motivating use cases are:
+
+* [Portals][]: Portal authors need to be able to identify whether the
+  container is being contacted by an uncontained process (running with
+  the user's full privileges), or whether it is being contacted by a
+  contained process (in a container created by Flatpak or Snap).
+
+* [dconf][]: Currently, a contained app either has full read/write access
+  to dconf, or no access. It should have read/write access to its own
+  subtree of dconf configuration space, and no access to the rest.
+
+At the moment, Flatpak runs a D-Bus proxy for each app instance that has
+access to D-Bus, connects to the appropriate bus on the app's behalf,
+and passes messages through. That proxy is in a container similar to the
+actual app instance, but not actually the same container; it is trusted
+to not pass messages through that it shouldn't pass through.
+The app-identification mechanism works in practice, but is Flatpak-specific,
+and has a known race condition due to process ID reuse and limitations
+in the metadata that the Linux kernel maintains for `AF_UNIX` sockets.
+In practice the use of X11 rather than Wayland in current systems is a much
+larger loophole in the container than this race condition, but we want to
+do better in future.
+
+Meanwhile, Snap does its sandboxing with AppArmor, on kernels where it
+is enabled both at compile-time (Ubuntu, openSUSE, Debian, Debian derivatives
+like Tails) and at runtime (Ubuntu, openSUSE and Tails, but not Debian by
+default). Ubuntu's kernel has extra AppArmor features that haven't yet
+gone upstream, some of which provide reliable app identification via
+LSM labels, which `dbus-daemon` can learn by querying its `AF_UNIX` socket.
+However, other kernels like the ones in openSUSE and Debian don't have
+those. The access-control (AppArmor *mediation*) is implemented in upstream
+dbus-daemon, but again doesn't work portably, and is not sufficiently
+fine-grained or flexible to do some of the things we'll likely want to do,
+particularly in dconf.
+
+After a lot of discussion with dconf maintainer [Allison Lortie][] and
+Flatpak maintainer [Alexander Larsson][], I think I have a plan for fixing
+this.
+
+This is all subject to change: see [fd.o #100344][] for the latest ideas.
+
+## Identity model
+
+Each user (uid) has some *uncontained* processes, plus 0 or more
+*containers*.
+
+The uncontained processes include dbus-daemon itself, desktop environment
+components such as gnome-session and gnome-shell, the container managers
+like Flatpak and Snap, and so on. They have the user's full privileges,
+and in particular they are allowed to do privileged things on the user's
+session bus (like running `dbus-monitor`), and act with the user's full
+privileges on the system bus. In generic information security jargon, they
+are the trusted computing base; in AppArmor jargon, they are unconfined.
+
+The containers are Flatpak apps, or Snap apps, or other app-container
+technologies like Firejail and AppImage (if they adopt this mechanism,
+which I hope they will), or even a mixture (different
+app-container technologies can coexist on a single system).
+They are containers (or container instances) and not "apps", because in
+principle, you could install `com.example.MyApp` 1.0, run it, and while
+it's still running, upgrade to `com.example.MyApp` 2.0 and run that; you'd
+have two containers for the same app, perhaps with different permissions.
+
+Each container has an *container type*, which is a reversed DNS
+name like `org.flatpak` or `io.snapcraft` representing the
+container technology, and an *app identifier*, an arbitrary non-empty
+string whose meaning is defined by the container technology. For Flatpak,
+that string would be another reversed DNS name like `com.example.MyGreatApp`;
+for Snap, as far as I can tell it would look like `example-my-great-app`.
+
+The container technology can also put arbitrary metadata on the D-Bus
+representation of a container, again defined and namespaced by the
+container technology. For instance, Flatpak would use some serialization
+of the same fields that go in the [Flatpak metadata][] file at the moment.
+
+Finally, the container has an opaque *container identifier* identifying
+a particular container instance. For example, launching `com.example.MyApp`
+twice (maybe different versions or with different command-line options
+to `flatpak run`) might result in two containers with different
+privileges, so they need to have different container identifiers.
+
+## Contained server sockets
+
+App-container managers like Flatpak and Snap would create an `AF_UNIX`
+socket inside the container, `bind()` it to an address that will be made
+available to the contained processes, and `listen()`, but not `accept()`
+any new connections. Instead, they would fd-pass the new socket to the
+dbus-daemon by calling a new method, and the dbus-daemon would proceed
+to `accept()` connections after the app-container manager has signalled
+that it has called both `bind()` and `listen()`. (See [fd.o #100344][]
+for full details.)
+
+Processes inside the container must not be allowed to contact the
+`AF_UNIX` socket used by the wider, uncontained system - if they could,
+the dbus-daemon wouldn't be able to distinguish between them and uncontained
+processes and we'd be back where we started. Instead, they should have the
+new socket bind-mounted into their container's `XDG_RUNTIME_DIR` and
+connect to that, or have the new socket set as their
+`DBUS_SESSION_BUS_ADDRESS` and be prevented from connecting to the
+uncontained socket in some other way.
+Those familiar with the [kdbus][] proposals a while ago might recognise
+this as being quite similar to kdbus' concept of *endpoints*, and I'm
+considering reusing that name.
+
+Along with the socket, the container manager would pass in the container's
+identity and metadata, and the method would return a unique, opaque
+identifier for this particular container instance. The basic fields
+(container technology, technology-specific app ID, container ID) should
+probably be added to the result of `GetConnectionCredentials()`, and
+there should be a new API call to get all of those plus the
+arbitrary technology-specific metadata.
+
+When a process from a container connects to the contained
+server socket, every message that it sends should also have the
+container instance ID in a new header field. This is OK even though
+[dbus-daemon does not (in general) forbid sender-specified future header
+fields][fd.o #100317], because any dbus-daemon that supported this new feature
+would guarantee to set that header field correctly, the existing
+Flatpak D-Bus proxy already filters out unknown header fields, and
+adding this header field is only ever a reduction in privilege.
+
+The reasoning for using the sender's container instance ID (as opposed to
+the sender's unique name) is for services like dconf to be able to treat
+multiple unique bus names as belonging to the same equivalence class of
+contained processes: instead of having to look up the container metadata
+once per unique name, dconf can look it up once per container instance
+the first time it sees a new identifier in a header field. For the second
+and subsequent unique names in the container, dconf can know that the
+container metadata and permissions are identical to the one it already saw.
+
+## Access control
+
+In principle, we could have the new identification feature without adding
+any new access control, by keeping Flatpak's proxies. However, in the
+short term that would mean we'd be adding new API to set up a socket for
+a container without any access control, and having to keep the proxies
+*anyway*, which doesn't seem great; in the longer term, I think we'd
+find ourselves adding a second new API to set up a socket for a container
+*with* new access control. So we might as well bite the bullet and go for
+the version with access control immediately.
+
+In principle, we could also avoid the need for new access control by
+ensuring that each service that will serve contained clients does its own.
+However, that makes it really hard to send broadcasts and not have them
+unintentionally leak information to contained clients - we would need to
+do something more like kdbus' approach to multicast, where services know
+who has subscribed to their multicast signals, and that is just not how
+dbus-daemon works at the moment. If we're going to have access control
+for broadcasts, it might as well also cover unicast.
+
+The plan is that messages from containers to the outside world will be mediated
+by a new access control mechanism, in parallel with dbus-daemon's current
+support for firewall-style rules in the XML bus configuration, AppArmor
+mediation, and SELinux mediation. A message would only be allowed through
+if the XML configuration, the new container access control mechanism,
+and the LSM (if any) all agree it should be allowed.
+
+By default, processes in a container can send broadcast signals,
+and send method calls and unicast signals to other processes in the same
+container. They can also receive method calls from outside the
+container (so that interfaces like `org.freedesktop.Application` can work),
+and send exactly one reply to each of those method calls. They cannot own
+bus names, communicate with other containers, or send file descriptors
+(which reduces the scope for denial of service).
+
+Obviously, that's not going to be enough for a lot of contained apps,
+so we need a way to add more access. I'm intending this to be purely
+additive (start by denying everything except what is always allowed,
+then add new rules), not a mixture of adding and removing access like
+the current XML policy language.
+
+There are two ways we've identified for rules to be added:
+
+* The container manager can pass a list of rules into the dbus-daemon
+  at the time it attaches the contained server socket, and they'll be
+  allowed. The obvious example is that an `org.freedesktop.Application`
+  needs to be allowed to own its own bus name. Flatpak apps'
+  implicit permission to talk to [portals][], and [Flatpak metadata][]
+  like `org.gnome.SessionManager=talk`, could also be added this way.
+
+* System or session services that are specifically designed to be used by
+  untrusted clients, like the version of `dconf` that Allison is working
+  on, could opt-in to having contained apps allowed to talk to them
+  (effectively making them a generalization of Flatpak portals).

(Diff truncated)
Add an anchor
diff --git a/2016/gtk-hackfest.mdwn b/2016/gtk-hackfest.mdwn
index 81df24f..2773d10 100644
--- a/2016/gtk-hackfest.mdwn
+++ b/2016/gtk-hackfest.mdwn
@@ -102,7 +102,7 @@ Other planned portals include:
 * notifications, probably based on freedesktop.org Notifications
 * video streaming (perhaps using Pinot, analogous to PulseAudio but for video)
 
-## Environment variables
+## <a id="environment-variables">Environment variables</a>
 
 GNOME on Wayland currently has a problem with environment variables:
 there are some traditional ways to set environment variables for X11

fix link syntax
diff --git a/2016/gtk-hackfest.mdwn b/2016/gtk-hackfest.mdwn
index 239614a..81df24f 100644
--- a/2016/gtk-hackfest.mdwn
+++ b/2016/gtk-hackfest.mdwn
@@ -203,7 +203,7 @@ being able to publish a walkthrough for
 
 ## GTK life-cycle and versioning
 
-The [life-cycle of GTK releases](gtk-versioning) has already been
+The [[life-cycle of GTK releases|gtk-versioning]] has already been
 mentioned here and elsewhere, and there are some interesting responses
 in the comments on my earlier blog post.
 

blog about the GTK hackfest
diff --git a/2016/gtk-hackfest.mdwn b/2016/gtk-hackfest.mdwn
new file mode 100644
index 0000000..239614a
--- /dev/null
+++ b/2016/gtk-hackfest.mdwn
@@ -0,0 +1,235 @@
+[[!meta title="GTK Hackfest 2016"]]
+[[!meta date="2016-06-20 19:37 +0100"]]
+[[!meta updated="2016-06-20 19:37 +0100"]]
+[[!meta copyright="Copyright © 2016 Simon McVittie"]]
+[[!meta license="[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)"]]
+[[!tag debian gtk flatpak ostree]]
+
+I'm back from the GTK hackfest in Toronto, Canada and mostly recovered from
+jetlag, so it's time to write up my notes on what we discussed there.
+
+Despite the hackfest's title, I was mainly there to talk about non-GUI
+parts of the stack, and technologies that fit more closely in what could
+be seen as the freedesktop.org platform than they do in GNOME. In particular,
+I'm interested in Flatpak as a way to deploy self-contained "apps" in a
+freedesktop-based, sandboxed runtime environment layered over
+[the Universal Operating System](https://www.debian.org/) and
+[its many derivatives](https://wiki.debian.org/Derivatives/Census),
+with both binary and source compatibility with other GNU/Linux distributions.
+
+I'm mainly only writing about discussions I was directly involved in:
+lots of what sounded like good discussion about the actual graphics toolkit
+went over my head completely :-)
+[More notes](https://wiki.gnome.org/Hackfests/GTK2016), mostly from Matthias
+Clasen, are available on the GNOME wiki.
+
+In no particular order:
+
+## Thinking with portals
+
+We spent some time discussing Flatpak's *portals*, mostly on Tuesday.
+These are the components that expose a subset of desktop functionality
+as D-Bus services that can be used by contained applications: they are
+part of the security boundary between a contained app and the rest of the
+desktop session. Android's *intents* are a similar concept seen elsewhere.
+While the portals are primarily designed for Flatpak, there's no real
+reason why they couldn't be used by other app-containment solutions
+such as Canonical's Snap.
+
+One major topic of discussion was their overall design and layout. Most
+portals will consist of a UX-independent part in Flatpak itself, together
+with a UX-specific implementation of any user interaction the portal
+needs. For example, the portal for file selection has a D-Bus service
+in Flatpak, which interacts with some UX-specific service that will
+pop up a standard UX-specific "Open" dialog — for GNOME and probably
+other GTK environments, that dialog is in (a branch of) GTK.
+
+A design principle that was reiterated in this discussion is that
+the UX-independent part should do as much as possible, with the
+UX-specific part only carrying out the user interactions that need
+to comply with a particular UX design (in the GTK case, GNOME's design).
+This minimizes the amount of work that needs to be redone for other
+desktop or embedded environments, while still ensuring that the other
+environments can have their chosen UX design. In particular, it's
+important that, as much as possible, the security- and performance-sensitive
+work (such as data transport and authentication) is shared between all
+environments.
+
+The aim is for portals to get the user's permission to carry out actions,
+while keeping it as implicit as possible, avoiding an "are you sure?" step
+where feasible. For example, if an application asks to open a file,
+the user's permission is implicitly given by them selecting the file
+in the file-chooser dialog and pressing OK: if they do not want this
+application to open a file at all, they can deny permission by cancelling.
+Similarly, if an application asks to stream webcam data, the UX we expect
+is for GNOME's Cheese app (or a similar non-GNOME app) to appear, open
+the webcam to provide a preview window so they can see what they are about
+to send, but not actually start sending the
+stream to the requesting app until the user has pressed a "Start" button.
+When defining the API "contracts" to be provided by applications in that
+situation, we will need to be clear about whether the provider is expected
+to obtain confirmation like this: in most cases I would anticipate that
+it is.
+
+One security trade-off here is that we have to have a small amount of
+trust in the providing app. For example, continuing the example of Cheese
+as a webcam provider, Cheese could (and perhaps should) be a contained
+app itself, whether via something like Flatpak, an LSM like AppArmor
+or both. If Cheese is compromised somehow, then whenever it is running, it
+would be technically possible for it to open the webcam, stream video and
+send it to a hostile third-party application. We concluded that this is an
+acceptable trade-off: each application needs to be trusted with the privileges
+that it needs to do its job, and we should not put up barriers that are easy
+to circumvent or otherwise serve no purpose.
+
+The main (only?) portal so far is the file chooser, in which the contained
+application asks the wider system to show an "Open..." dialog, and if the user
+selects a file, it is returned to the contained application through a FUSE
+filesystem, the *document portal*. The reference implementation of the UX for
+this is in GTK, and is basically a `GtkFileChooserDialog`. The intention is
+that other environments such as KDE will substitute their own equivalent.
+
+Other planned portals include:
+
+* image capture (scanner/camera)
+* opening a specified URI
+  - this needs design feedback on how it should work for non-http(s)
+* sharing content, for example on social networks (like Android's Sharing menu)
+* proxying joystick/gamepad input (perhaps via Wayland or FUSE, or perhaps
+  by modifying libraries like SDL with a new input source)
+* network proxies (`GProxyResolver`) and availability (`GNetworkMonitor`)
+* contacts/address book, probably vCard-based
+* notifications, probably based on freedesktop.org Notifications
+* video streaming (perhaps using Pinot, analogous to PulseAudio but for video)
+
+## Environment variables
+
+GNOME on Wayland currently has a problem with environment variables:
+there are some traditional ways to set environment variables for X11
+sessions or login shells using shell script fragments (`/etc/X11/Xsession.d`,
+`/etc/X11/xinit/xinitrc.d`, `/etc/profile.d`), but these do not apply to
+Wayland, or to noninteractive login environments like `cron` and
+`systemd --user`. We are also keen to avoid requiring a Turing-complete shell
+language during session startup, because it's difficult to reason about
+and potentially rather inefficient.
+
+Some uses of environment variables can be dismissed as unnecessary or even
+unwanted, similar to the statement in Debian Policy §9.9: "A program must not
+depend on environment variables to get reasonable defaults." However,
+there are two common situations where environment variables can be necessary
+for proper OS integration: search-paths like `$PATH`, `$XDG_DATA_DIRS` and
+`$PYTHONPATH` (particularly necessary for things like Flatpak), and
+optionally-loaded modules like `$GTK_MODULES` and `$QT_ACCESSIBILITY`
+where a package influences the configuration of another package.
+
+There is a stopgap solution in GNOME's gdm display manager,
+`/usr/share/gdm/env.d`, but this is gdm-specific and
+insufficiently expressive to provide the functionality needed by
+Flatpak: "set `XDG_DATA_DIRS` to its specified default value if unset,
+then add a couple of extra paths".
+
+`pam_env` comes closer — PAM is run at every transition from "no user logged
+in" to "user can execute arbitrary code as themselves" — but it doesn't
+support `.d` fragments, which are required if we want distribution packages
+to be able to extend search paths. `pam_env` also turns off per-user
+configuration by default, citing security concerns.
+
+I'll write more about this when I have a concrete proposal for how to solve it.
+I think the best solution is probably a PAM module similar to `pam_env` but
+supporting `.d` directories, either by modifying `pam_env` directly or
+out-of-tree, combined with clarifying what the security concerns for
+per-user configuration are and how they can be avoided.
+
+## Relocatable binary packages
+
+On Windows and OS X, various GLib APIs automatically discover where the
+application binary is located and use search paths relative to that;
+for example, if `C:\myprefix\bin\app.exe` is running, GLib might put
+`C:\myprefix\share` into the result of `g_get_system_data_dirs()`,
+so that the application can ask to load `app/data.xml` from the data
+directories and get `C:\myprefix\share\app\data.xml`. We would like
+to be able to do the same on Linux, for example so that the apps in a
+Flatpak or Snap package can be constructed from RPM or dpkg packages without
+needing to be recompiled for a different `--prefix`, and so that other
+third-party software packages like the games on Steam and gog.com can
+easily locate their own resources.
+
+Relatedly, there are currently no well-defined semantics for what happens
+when a `.desktop` file or a D-Bus `.service` file has `Exec=./bin/foo`.
+The meaning of `Exec=foo` is well-defined (it searches `$PATH`) and the
+meaning of `Exec=/opt/whatever/bin/foo` is obvious. When this came up in
+D-Bus previously, my assertion was that the meaning should be the same as
+in `.desktop` files, whatever that is.
+
+We agreed to propose that the meaning of a non-absolute path in a `.desktop`
+or `.service` file should be interpreted relative to the directory
+where the `.desktop` or `.service` file was found: for example, if
+`/opt/whatever/share/applications/foo.desktop` says `Exec=../../bin/foo`,
+then `/opt/whatever/bin/foo` would be the right thing to execute.
+While preparing a mail to the freedesktop and D-Bus mailing lists proposing
+this, I found that I had
+[proposed the same thing](https://lists.freedesktop.org/archives/xdg/2014-September/013339.html)
+[almost 2 years ago](https://lists.freedesktop.org/archives/dbus/2014-September/016330.html)...
+this time I hope I can actually make it happen!
+
+## Flatpak and OSTree bug fixing
+
+On the way to the hackfest, and while the discussion moved to topics that I
+didn't have useful input on, I spent some time fixing up the Debian packaging
+for Flatpak and its dependencies. In particular, I did my first upload
+as a co-maintainer of [bubblewrap](https://tracker.debian.org/news/776053),
+uploaded ostree to unstable (with the known limitation that [the grub, dracut
+and systemd integration is missing for now](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=824650)
+since I haven't been able to test it yet), got
+most of the way through packaging Flatpak 0.6.5 (which I'll upload soon),
+cherry-picked the right patches to make ostree compile on Debian 8 in an effort
+to make backports trivial, and spent some time disentangling
+[a flatpak test failure](https://github.com/flatpak/flatpak/commit/1d185f7dd6c4537726a86629b9ddcb516767fcb7)
+which was breaking the Debian package's installed-tests.
+I'm still looking into
+[ostree test failures on little-endian MIPS](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=827473),
+which I was able to reproduce on a Debian porterbox just before the end of the
+hackfest.
+
+## OSTree + Debian

(Diff truncated)
Comment moderation
diff --git a/2016/gtk-versioning/comment_5_40b982666c386cf75df37b221eb2ed60._comment b/2016/gtk-versioning/comment_5_40b982666c386cf75df37b221eb2ed60._comment
new file mode 100644
index 0000000..a301ba4
--- /dev/null
+++ b/2016/gtk-versioning/comment_5_40b982666c386cf75df37b221eb2ed60._comment
@@ -0,0 +1,32 @@
+[[!comment format=mdwn
+ username="smcv"
+ avatar="http://cdn.libravatar.org/avatar/c0f354dae99f5d9eb0474518bc507905"
+ subject="themes"
+ date="2016-06-20T12:11:01Z"
+ content="""
+> *3.20 was supposed to be the last big break, and after this the theme API was supposed to be stable - Matthias blogged about this. Now, with continual breaks, it seems that this promise is basically out of the window. As a theme author I again need to track the breaking releases of GTK and potentially port my theme each time.*
+
+That's a valid concern, and I don't know what the policy will be regarding themes.
+
+I suspect that in practice theming is always going to be \"interesting times\"
+territory, because a theme potentially needs to know about every widget,
+and it's easy for a relatively minor bug to make a particular application
+unusable (through a combination of factors accidentally producing
+white-on-white text or whatever).
+
+I'm assuming that GTK will break API/ABI where it's necessary to enable future work,
+but will not break API/ABI just for the sake of it. I don't know what that means for
+themes: perhaps the fact that they touch every widget means they're likely to be
+affected by at least one breakage, but perhaps that's balanced out by the move
+from unique GTK'isms to something very close to standard W3C CSS.
+
+One interesting side effect of being more willing to break API/ABI is that the
+GTK maintainers would be more free to expose APIs they aren't 100% sure about
+being able to retain for multiple years of development, such as the CSS
+\"gadget\" APIs that Matthias mentioned in his blog post - if I'm understanding
+it correctly, that would make  it much easier for custom widgets outside GTK
+to be \"first class citizens\" with the same level of CSS support as the widgets
+in GTK. If an API turns out to have been a bad idea, it can be dropped
+immediately (during the SONAME-breaking development period), and won't
+show up in the next 2ish-year major release.
+"""]]

Comment moderation
diff --git a/2016/gtk-versioning/comment_4_e32139aa9478cda4fc065043bc483869._comment b/2016/gtk-versioning/comment_4_e32139aa9478cda4fc065043bc483869._comment
new file mode 100644
index 0000000..cfbef95
--- /dev/null
+++ b/2016/gtk-versioning/comment_4_e32139aa9478cda4fc065043bc483869._comment
@@ -0,0 +1,53 @@
+[[!comment format=mdwn
+ username="smcv"
+ avatar="http://cdn.libravatar.org/avatar/c0f354dae99f5d9eb0474518bc507905"
+ subject="comment 4"
+ date="2016-06-20T11:56:52Z"
+ content="""
+> *There will definitely be unstable-using applications (maybe a third party developer needed a feature in GTK 4.2 but is now busy for a short while and its API broke in 4.4) that either stop being developed completely, or whose maintainer (either in GNOME or out of it - even within GNOME inactive maintainers will mean things get broken from time to time until the build fixers show up, unless a policy like 'no GTK release until all modules build with it').*
+
+We did touch on this during discussions at the hackfest. Someone (sorry, I
+forget who) made the point that within GNOME, if a module becomes
+unmaintained-in-practice, it's considered valid for anyone else in GNOME to
+land fixes. That hopefully mitigates the problem within GNOME.
+
+Outside GNOME, I think the recommendation would likely be that maintainers
+shouldn't get on the unstable train unless they are willing to ride it all
+the way to the next station :-) With semi-frequent stable releases, sticking
+to a stable release puts you much less far behind than in GTK's historical
+schedule.
+
+> *To get around this, it seems to me that distribution maintainers will have
+> to adopt a 'remove first' policy so that they don't become burned out.
+> This is where we have to hope that people don't use the unstable GTK+.*
+
+To some extent, Debian already has that policy via autoremovals. If
+dependent packages don't want to be autoremoved, it is up to the maintainer
+of the dependent package to fix it - this sort of thing is why we call
+ourselves Debian maintainers, not Debian packagers.
+
+> *Let's say that Debian release X freezes when GTK 5.2 (unstable) and its
+> corresponding GNOME is current. Would you expect the GNOME maintainers
+> to avoid packaging 5.2? To avoid updating GNOME to this release but still
+> package GTK? Or to package all of it?*
+
+This would be a decision for the GTK and GNOME maintainers based on how much
+work it is and how much time is available, but if it was up to me, I'd expect
+that we'd package both GTK 4.0 and GTK 5.2, together with the version of
+GNOME that corresponds to 5.2.
+
+> *If the latter, what is the maintenance commitment of the GTK+ team to this
+> unstable-but-stable-in-the-GNOME-sense branch? Can we expect bugfixes to be
+> cherry-picked for a few months, as normal, even if the API has moved on in
+> master*
+
+I would hope so. Note that the stable branches already largely exist for
+distribution maintainers' benefit, and as far as I can see, what goes into
+those branches is often already driven by what distribution maintainers
+want those branches to look like.
+
+It's possible that the \"LTS\" branches might become even more conservative in
+what they will accept, taking only changes with a particularly good ratio
+of severity of bugs fixed / (probability × severity) of regressions expected,
+a lot like a Debian stable release.
+"""]]

Comment moderation
diff --git a/2016/gtk-versioning/comment_3_3d8c92c0acf0b8c28677b9b527c87ca4._comment b/2016/gtk-versioning/comment_3_3d8c92c0acf0b8c28677b9b527c87ca4._comment
new file mode 100644
index 0000000..71568eb
--- /dev/null
+++ b/2016/gtk-versioning/comment_3_3d8c92c0acf0b8c28677b9b527c87ca4._comment
@@ -0,0 +1,37 @@
+[[!comment format=mdwn
+ username="smcv"
+ avatar="http://cdn.libravatar.org/avatar/c0f354dae99f5d9eb0474518bc507905"
+ subject="comment 3"
+ date="2016-06-20T11:37:46Z"
+ content="""
+> *for the sake of clarity I think it's good to mention that Qt doesn't breaks API+ABI in their major versions, normally ~10 years apart from each other*
+
+But you/they did break API+ABI between Qt 3 and Qt 4, and then again between Qt 4
+and Qt 5, right? That's the parallel I was trying to draw.
+
+This proposal does have more frequent major versions than Qt, which is a
+trade-off: it means there are potentially more versions \"in the wild\" at
+any given time, but it hopefully also reduces the need for projects that don't
+closely track GTK and GNOME to depend on the version that is the current focus of
+development, reducing the probability of a change breaking those projects.
+
+If GTK contributors want to support a particular branch for 10 years, they
+are of course welcome to do so - GTK 2 is still maintained, although it's
+really showing its age by now.
+
+> *although we actually needed some ugly hacks in between*
+
+This touches on the reason that I think it's necessary to be willing to break ABI
+sometimes, and not necessarily a bad thing as long as you're honest about it (by
+bumping the SONAME). It is always *possible* to avoid breaking ABI, but taking
+that too far can easily make new features or bug-fixes prohibitively expensive,
+either in paid contributors' time (direct financial cost) or
+volunteers' time (not a direct financial cost, but also a finite resource).
+
+I used to work on Telepathy, which tried very hard not to break ABI, and suffered
+for it: paid developers adding new features found it hard to be cost-effective,
+while volunteer community members were put off by the amount of time and effort
+that it took to get anything from idea to merge. Telepathy 1.0 (the first version
+to do a \"hard\" ABI break since the very early days of the project) was started
+but never finished, partly as a result of this high cost.
+"""]]

Comment moderation
diff --git a/2016/gtk-versioning/comment_1_c71a48836bb8b10c9129728fffd7e6af._comment b/2016/gtk-versioning/comment_1_c71a48836bb8b10c9129728fffd7e6af._comment
new file mode 100644
index 0000000..1aedc8d
--- /dev/null
+++ b/2016/gtk-versioning/comment_1_c71a48836bb8b10c9129728fffd7e6af._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="http://perezmeyer.blogspot.co.uk/"
+ subject="Maybe not so similar to Qt"
+ date="2016-06-14T14:22:06Z"
+ content="""
+Hi Simon! I think you gave the right example with respect to parallel installations with Qt (although we actually needed some ugly hacks in between). But for the sake of clarity I think it's good to mention that Qt doesn't breaks API+ABI in their major versions, normally ~10 years apart from each other.
+
+If you build an app with Qt 4.0.0 it would still be able to run with Qt 4.8, the latest in the series which happened ~10 years later. Same goes for Qt5. The only thing that we don't warrant with Qt is downgrading the Qt version: if you build an app with Qt 5.4 you will surely not be able to run it against Qt 5.0.
+
+Hope that makes thing clearer :)
+"""]]
diff --git a/2016/gtk-versioning/comment_2_8f58ec79c059dd8a061c8f8c1b2ab10f._comment b/2016/gtk-versioning/comment_2_8f58ec79c059dd8a061c8f8c1b2ab10f._comment
new file mode 100644
index 0000000..545542c
--- /dev/null
+++ b/2016/gtk-versioning/comment_2_8f58ec79c059dd8a061c8f8c1b2ab10f._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="https://launchpad.net/~laney"
+ nickname="laney"
+ avatar="http://cdn.libravatar.org/avatar/0278f207f1ee700c7d640a496c55d17fc308be0bbdd7e35b3ee26d22b9952416"
+ subject="Downstream concerns"
+ date="2016-06-15T09:12:16Z"
+ content="""
+Thanks to you all for thinking about these things, they are important issues. Sorry that this gets a bit rambly.
+
+I already mentioned some of my concerns in a conversation on IRC, but I want to write them down here - and maybe you want to respond.
+
+It feels like the plan makes sense as far as there is a stable target and an unstable one which application developers can choose between depending on what they are willing to sign up for. It's probably not controversial to say that things are unlikely to end up being that neat in reality. There will definitely be unstable-using applications (maybe a third party developer needed a feature in GTK 4.2 but is now busy for a short while and its API broke in 4.4) that either stop being developed completely, or whose maintainer (either in GNOME or out of it - even within GNOME inactive maintainers will mean things get broken from time to time until the build fixers show up, unless a policy like 'no GTK release until all modules build with it').
+
+When a new GNOME release which depends on an unstable GTK+ happens, and distributors want to ship this, the new policy says this is a transition every time. Fine, we know how to deal with those in distributions - but, at least for Debian and Ubuntu, it means that *every* reverse dependency needs to be ported or removed. Each of the (temporarily or not) unmaintained ones are going to be a drag on this, and a burden on GTK+'s distribution maintainer - they will analyse the breakages and either try to fix or remove the package. That's a drag in both mental effort and time, and one that this scheme will give distributors every 6 months if they want to ship current GNOME. To get around this, it seems to me that distribution maintainers will have to adopt a 'remove first' policy so that they don't become burned out. This is where we have to hope that people don't use the unstable GTK+.
+
+Should LTS and stable Debian ship the GTK and GNOME that correspond to the current-stable release at the time? Let's say that Debian release X freezes when GTK 5.2 (unstable) and its corresponding GNOME is current. Would you expect the GNOME maintainers to avoid packaging 5.2? To avoid updating GNOME to this release but still package GTK? Or to package all of it? If the latter, what is the maintenance commitment of the GTK+ team to this unstable-but-stable-in-the-GNOME-sense branch? Can we expect bugfixes to be cherry-picked for a few months, as normal, even if the API has moved on in master and is shipping such an intermediate (\"non-LTS\" in your analogy\" version in an LTS/stable advisable?
+
+Finally, themes. GTK 3 below 3.20 never promised stability in the theme API, and theme authors certainly have had to catch up with GTK's changes every cycle. Because of this, maintaining a theme was an onerous ongoing commitment. 3.20 was supposed to be the last big break, and after this the theme API was supposed to be stable - [Matthias blogged about this](https://blogs.gnome.org/mclasen/2015/11/20/a-gtk-update/). Now, with continual breaks, it seems that this promise is basically out of the window. As a theme author I *again* need to track the breaking releases of GTK and potentially port my theme each time. It feels like we had *just* managed to get there - the next stable release after the promise isn't even out yet - and now the rug is being pulled away again. Having more parallel-installable releases out there actually makes the situation a little bit worse since theme authors will have to maintain branches for each stable release until its obsolescence. You might think \"well, having to rewrite your theme once every 2 years instead of every 6 months is an improvement\", but that ignores the promise as previously mentioned - and it's not right to say that it is every 2 years. If you want your theme to be usable on current GNOME, based on unstable GTK, you need to be developing your theme for that. So the commitment is still an ongoing one.
+
+I hope these comments are helpful at outlining some concerns of a downstream person. Happy hackfest. :)
+
+"""]]

GTK versioning (this post brought to you by the 3 Brewers, Toronto)
diff --git a/2016/gtk-versioning.mdwn b/2016/gtk-versioning.mdwn
new file mode 100644
index 0000000..61ad02a
--- /dev/null
+++ b/2016/gtk-versioning.mdwn
@@ -0,0 +1,102 @@
+[[!meta title="GTK versioning and distributions"]]
+[[!meta date="2016-06-13T21:56:00-0400"]]
+[[!meta updated="2016-06-13T21:56:00-0400"]]
+[[!meta copyright="Copyright © 2016 Simon McVittie"]]
+[[!meta license="[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)"]]
+[[!tag debian gtk]]
+
+Allison Lortie has provoked a lot of comment with her blog post on
+[a new proposal for how GTK is versioned](https://blogs.gnome.org/desrt/2016/06/13/gtk-4-0-is-not-gtk-4/).
+Here's some more context from the discussion at the GTK hackfest that
+prompted that proposal: there's actually quite a close analogy in
+how new Debian versions are developed.
+
+The problem we're trying to address here is the two sides of a trade-off:
+
+* Without new development, a library (or an OS) can't go anywhere new
+* New development sometimes breaks existing applications
+
+Historically, GTK has aimed to keep compatible within a major version,
+where major versions are rather far apart (GTK 1 in 1998, GTK 2 in
+2002, GTK 3 in 2011, GTK 4 somewhere in the future). Meanwhile, fixing
+bugs, improving performance and introducing new features sometimes
+results in major changes behind the scenes. In an ideal world, these
+behind-the-scenes changes would never break applications; however, the
+world isn't ideal. (The Debian analogy here is that as much as we
+aspire to having the upgrade from one stable release to the next not break
+anything at all, I don't think we've ever achieved that in practice -
+we still ask users to read the release notes, even though ideally
+that wouldn't be necessary.)
+
+In particular, the perceived cost of doing a proper ABI break (a fully
+parallel-installable GTK 4) means there's a strong temptation to make
+changes that don't actually remove or change C symbols, but are clearly
+an ABI break, in the sense that an application that previously worked
+and was considered correct no longer works. A prominent recent example is
+the theming changes in GTK 3.20: the ABI in terms of functions available
+didn't change, but what happens when you call those functions changed in
+an incompatible way. This makes GTK hard to rely on for applications
+outside the GNOME release cycle, which is a problem that needs to
+be fixed (without stopping development from continuing).
+
+The goal of
+[the plan we discussed today](https://blogs.gnome.org/desrt/2016/06/13/gtk-4-0-is-not-gtk-4/)
+is to decouple the latest branch of development, which moves fast and
+sometimes breaks API, from the API-stable branches, which only get bug
+fixes. This model should look quite familiar to Debian contributors,
+because it's a lot like the way we release Debian and Ubuntu.
+
+In Debian, at any given time we have a development branch
+(testing/unstable) - currently "stretch", the future Debian 9. We
+also have some stable branches, of which the most recent are Debian
+8 "jessie" and Debian 7 "wheezy". Different users of Debian have
+different trade-offs that lead them to choose one or the other of
+these. Users who value stability and want to avoid unexpected changes,
+even at a cost in terms of features and fixes for non-critical bugs,
+choose to use a stable release, preferably the most recent; they only
+need to change what they run on top of Debian for OS API changes (for
+instance webapps, local scripts, or the way they interact with the GUI)
+approximately every 2 years, or perhaps less often than that with the
+Debian-LTS project supporting non-current stable releases. Meanwhile,
+users who value the latest versions and are willing to work with a
+"moving target" as a result choose to use testing/unstable.
+
+The GTK analogy here is really quite close. In the new versioning model,
+library users who value stability over new things would prefer to use
+a stable-branch, ideally the latest; library users who want the latest
+features, the latest bug-fixes and the latest new bugs would use the
+branch that's the current focus of development. In practice we expect
+that the latter would be mostly GNOME projects. There's been some
+discussion at the hackfest about how often we'd have a new
+stable-branch: the fastest rate that's been considered is a stable-branch
+every 2 years, similar to Ubuntu LTS and Debian, but there's no consensus
+yet on whether they will be that frequent in practice.
+
+How many stable versions of GTK would end up shipped in Debian depends
+on how rapidly projects move from "old-stable" to "new-stable" upstream,
+how much those projects' Debian maintainers are willing to patch them
+to move between branches, and how many versions the release team will
+tolerate. Once we reach a steady state, I'd hope that we might have
+1 or 2 stable-branched versions active at a time, packaged as separate
+parallel-installable source packages (a lot like how we handle Qt).
+GTK 2 might well stay around as an additional active version just
+from historical inertia. The stable versions are intended to be
+fully parallel-installable, just like the situation with GTK 1.2,
+GTK 2 and GTK 3 or with the major versions of Qt.
+
+For the "current development" version, I'd anticipate that we'd probably
+only ship one source package, and do ABI transitions for one version
+active at a time, a lot like how we deal with libgnome-desktop and the
+evolution-data-server family of libraries. Those versions would have
+parallel-installable runtime libraries but non-parallel-installable
+development files, again similar to libgnome-desktop.
+
+At the risk of stretching the Debian/Ubuntu analogy too far, the
+intermediate "current development" GTK releases that would accompany
+a GNOME release are like Ubuntu's non-LTS suites: they're more up to
+date than the fully stable releases (Ubuntu LTS, which has a release
+schedule similar to Debian stable), but less stable and not supported
+for as long.
+
+Hopefully this plan can meet both of its goals: minimize breakage for
+applications, while not holding back the development of new APIs.

Blog about xdg-app^WFlatpak
diff --git a/2016/flatpak.mdwn b/2016/flatpak.mdwn
new file mode 100644
index 0000000..6bb88ab
--- /dev/null
+++ b/2016/flatpak.mdwn
@@ -0,0 +1,72 @@
+[[!meta title="Flatpak in Debian"]]
+[[!meta date="2016-06-05T12:24:00+0100"]]
+[[!meta updated="2016-06-05T12:24:00+0100"]]
+[[!meta copyright="Copyright © 2016 Simon McVittie"]]
+[[!meta license="[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)"]]
+[[!tag debian xdg-app flatpak]]
+
+Quite a lot has happened in xdg-app since
+[[last time I blogged about it|xdg-app]]. Most noticeably, it isn't called
+xdg-app any more, having been renamed to [Flatpak](http://flatpak.org/).
+It is now available in Debian experimental under that name, and the
+xdg-app package that was briefly there has been removed. I'm currently
+in the process of updating Flatpak to the latest version 0.6.4.
+
+The privileged part has also spun off into a separate project,
+[Bubblewrap](https://github.com/projectatomic/bubblewrap), which recently
+had its first release (0.1.0). This is intended as a common component
+with which unprivileged users can start a container in a way that
+won't let them escalate privileges, like a more flexible version of
+[linux-user-chroot](https://git.gnome.org/browse/linux-user-chroot/).
+
+Bubblewrap has also been made available in Debian, maintained by Laszlo
+Boszormenyi (also maintainer of linux-user-chroot). Yesterday I sent a patch
+to [update Laszlo's packaging for 0.1.0](https://bugs.debian.org/826358).
+I'm hoping to become a co-maintainer to upload that myself, since I suspect
+Flatpak and Bubblewrap might need to track each other quite closely.
+For the moment, Flatpak still uses its own internal copy of Bubblewrap,
+but [I consider that to be a bug](https://bugs.debian.org/824647) and
+I'd like to be able to fix it soon.
+
+At some point I also want to experiment with using Bubblewrap to
+sandbox some of the game engines that are packaged in Debian: networked
+games are a large attack surface, and typically consist of the sort
+of speed-optimized C or C++ code that is an ideal home for security
+vulnerabilities. I've already made some progress on jailing game engines
+with AppArmor, but making sensitive files completely invisible to the
+game engine seems even better than preventing them from being opened.
+
+Next weekend I'm going to be heading to Toronto for the
+[GTK Hackfest](https://wiki.gnome.org/Hackfests/GTK2016), primarily to to
+talk to GNOME and Flatpak developers about their plans for sandboxing,
+portals and Flatpak. Hopefully we can make some good progress there: the more I
+know about the state of software security, the less happy I am with random
+applications all being equally privileged. Newer display technologies like
+Wayland and Mir represent an opportunity to plug [one of the largest
+holes in typical application containerization](https://mjg59.dreamwidth.org/42320.html),
+which is a major step in bringing sandboxes like Flatpak and Snap from
+proof-of-concept to a practical improvement in security.
+
+Other next steps for Flatpak in Debian:
+
+* To get into the next stable release (Debian 9), Flatpak needs to move
+  from `experimental` into `unstable` and `testing`. I've taken the
+  first step towards that by uploading `libgsystem` to unstable.
+  Before Flatpak can follow, OSTree also needs to move.
+* Now that it's in Debian, please [report bugs in the usual Debian
+  way](https://www.debian.org/Bugs/Reporting) or send patches to fix
+  bugs: [Flatpak](http://bugs.debian.org/src:flatpak),
+  [OSTree](http://bugs.debian.org/src:ostree),
+  [libgsystem](http://bugs.debian.org/src:libgsystem).
+* In particular, there are some OSTree bugs tagged `help`. I'd
+  appreciate contributions to the OSTree packaging from people
+  who are interested in using it to deploy `dpkg`-based operating systems -
+  I'm primarily looking at it from the Flatpak perspective, so the boot/OS
+  side of it isn't so well tested. Red Hat have `rpm-ostree`,
+  and I believe [Endless](https://endlessm.com/) do something analogous
+  to build OS images with `dpkg`, but I haven't had a chance to look into
+  that in detail yet.
+* Co-maintainers for [Flatpak](https://tracker.debian.org/pkg/flatpak),
+  [OSTree](https://tracker.debian.org/pkg/ostree),
+  [libgsystem](https://tracker.debian.org/pkg/libgsystem) would also
+  be very welcome.

adjust acknowledgements
diff --git a/2016/xdg-app.mdwn b/2016/xdg-app.mdwn
index 9820b25..0b6c32b 100644
--- a/2016/xdg-app.mdwn
+++ b/2016/xdg-app.mdwn
@@ -447,11 +447,14 @@ in having such a simplistic demo to go alongside the various GNOMEish apps.
 
 Acknowledgements:
 
-* [Betacowork Coworking Brussels](http://www.betacowork.com/),
-  [ICAB Business & Technology Incubator](http://www.icabrussel.be/) and
-  [Collabora](https://www.collabora.com/) and
-  [the GNOME Foundation](https://www.gnome.org/foundation/) sponsored the
+* [Betacowork Coworking Brussels](http://www.betacowork.com/) and
+  [ICAB Business & Technology Incubator](http://www.icabrussel.be/)
+  hosted the hackfest, with [Collabora](https://www.collabora.com/)
+  providing snacks, and
+  [the GNOME Foundation](https://www.gnome.org/foundation/) supporting the
   hackfest in general;
 * Collabora also sponsored my travel, accommodation and time;
 * my colleague [Philip Withnall](https://tecnocode.co.uk/) organised the
-  hackfest
+  hackfest.
+
+Thanks to all those!

https everywhere
diff --git a/2016/xdg-app.mdwn b/2016/xdg-app.mdwn
index 6c35ac3..9820b25 100644
--- a/2016/xdg-app.mdwn
+++ b/2016/xdg-app.mdwn
@@ -28,7 +28,7 @@ that space:
   tend to test on a vaguely recent Ubuntu LTS and leave it at that.
 
 * There's no widely-supported mechanism for installing third-party
-  applications as an ordinary user. [gog.com](http://www.gog.com/)
+  applications as an ordinary user. [gog.com](https://www.gog.com/)
   used to distribute Ubuntu- and Debian-compatible `.deb` files,
   but installing a `.deb` involves running arbitrary vendor-supplied
   scripts as root, which should worry anyone who wants any sort of
@@ -98,7 +98,7 @@ Source code:
 
 Binaries (no trust path, so only use these if you have a test VM):
 
-* `deb http://people.debian.org/~smcv/xdg-app xdg-app main`
+* `deb https://people.debian.org/~smcv/xdg-app xdg-app main`
 
 ## The "Hello, World" of xdg-apps
 

post about GNOME DX hackfest and xdg-app
diff --git a/2016.mdwn b/2016.mdwn
new file mode 100644
index 0000000..2a95548
--- /dev/null
+++ b/2016.mdwn
@@ -0,0 +1 @@
+[[!map pages="2016/* and copyright(*)" show=title]]
diff --git a/2016/xdg-app.mdwn b/2016/xdg-app.mdwn
new file mode 100644
index 0000000..6c35ac3
--- /dev/null
+++ b/2016/xdg-app.mdwn
@@ -0,0 +1,457 @@
+[[!meta title="GNOME Developer Experience hackfest: xdg-app + Debian"]]
+[[!meta date="2016-01-30T19:07:45+0100"]]
+[[!meta updated="2016-01-30T19:07:45+0100"]]
+[[!meta copyright="Copyright © 2016 Collabora Ltd."]]
+[[!meta license="[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)"]]
+[[!tag debian xdg-app]]
+
+Over the last few days I've been at the GNOME Developer Experience hackfest
+in Brussels, looking into
+[xdg-app](https://wiki.freedesktop.org/www/Software/xdg-app/)
+and how best to use it in Debian and Debian derivatives.
+
+xdg-app is basically a way to run "non-core" software on Linux distributions,
+analogous to apps on Android and iOS. It doesn't replace distributions
+like Debian or packaging systems, but it adds a layer above them. It's
+mostly aimed towards third-party apps obtained from somewhere that isn't
+your distribution vendor, aiming to address a few long-standing problems in
+that space:
+
+* There's no single ABI that can be called "a standard Linux system" in
+  the same way there would be for Windows or OS X or Android or whatever,
+  apart from LSB which is rather limited. Testing that a third-party app
+  "works on Linux", or even "works on stable Linux releases from 2015",
+  involves a combinatorial explosion of different distributions, desktop
+  environments and local configurations. Steam uses
+  [the Steam Runtime](https://github.com/ValveSoftware/steam-runtime),
+  a chroot environment closely resembling Ubuntu 12.04 LTS; other vendors
+  tend to test on a vaguely recent Ubuntu LTS and leave it at that.
+
+* There's no widely-supported mechanism for installing third-party
+  applications as an ordinary user. [gog.com](http://www.gog.com/)
+  used to distribute Ubuntu- and Debian-compatible `.deb` files,
+  but installing a `.deb` involves running arbitrary vendor-supplied
+  scripts as root, which should worry anyone who wants any sort of
+  privilege-separation. (They have now switched to executable self-extracting
+  installers, which involve running arbitrary vendor-supplied scripts
+  as an ordinary user... better, but not perfect.)
+
+* Relatedly, the third-party application itself runs with the user's
+  full privileges: a malicious or security-buggy third-party application
+  [can do more or less anything](https://xkcd.com/1200/), unless you
+  either switch to a different uid to run third-party apps, or
+  use a carefully-written, app-specific AppArmor profile or equivalent.
+
+To address the first point, each application uses a specified "runtime",
+which is available as /usr inside its sandbox. This can be used to run
+application bundles with multiple, potentially incompatible sets of
+dependencies within the same desktop environment. A runtime can be
+updated within its branch - for instance, if an application uses the
+"GNOME 3.18" runtime (consisting of a basic Linux system, the GNOME 3.18
+libraries, other related libraries like Mesa, and their recursive dependencies
+like libjpeg), it can expect to see minor-version updates from GNOME 3.18.x
+(including any security updates that might be necessary for the bundled
+libraries), but not a jump to GNOME 3.20.
+
+To address the second issue, the plan is for application bundles
+to be available as a single file, containing metadata (such as
+the runtime to use), the app itself, and any dependencies that
+are not available in the runtime (which the app vendor is responsible for
+updating if necessary). However, the primary way to distribute
+and upgrade runtimes and applications is to package them as
+[OSTree](https://wiki.gnome.org/Projects/OSTree) repositories, which
+provide a git-like content-addressed filesystem, with efficient updates
+using binary deltas. The resulting files are hard-linked into place.
+
+To address the last point, application bundles run partially isolated
+from the wider system, using containerization techniques such as namespaces
+to prevent direct access to system resources. Resources from outside the
+sandbox can be accessed via "portal" services, which are responsible for
+access control; for example, the Documents portal (the only one, so far)
+displays an "Open" dialog outside the sandbox, then allows the application to
+access only the selected file.
+
+## xdg-app for Debian
+
+One thing I've been doing at this hackfest is improving the existing
+[Debian/Ubuntu packaging](https://launchpad.net/~alexlarsson/+archive/ubuntu/xdg-app)
+for xdg-app (and its dependencies ostree and libgsystem), aiming to get it
+into a state where I can upload it to Debian experimental. Because xdg-app
+aims to be a general freedesktop project, I'm currently intending to make
+it part of the "Utopia" packaging team alongside projects like D-Bus
+and polkit, but I'm open to suggestions if people want to co-maintain
+it elsewhere.
+
+In the process of updating xdg-app, I sent various patches to Alex,
+mostly fixing build and test issues, which are in the new 0.4.8 release.
+
+I'd appreciate co-maintainers and further testing for this stuff,
+particularly ostree: ostree is primarily a whole-OS deployment technology,
+which isn't a use-case that I've tested, and in particular ostree-grub2
+probably doesn't work yet.
+
+Source code:
+
+* <https://anonscm.debian.org/cgit/users/smcv/libgsystem.git>
+* <https://anonscm.debian.org/cgit/users/smcv/ostree.git>
+* <https://anonscm.debian.org/cgit/users/smcv/xdg-app.git>
+
+Binaries (no trust path, so only use these if you have a test VM):
+
+* `deb http://people.debian.org/~smcv/xdg-app xdg-app main`
+
+## The "Hello, World" of xdg-apps
+
+Another thing I set out to do here was to make a runtime and an app
+out of Debian packages. Most of the test applications in and around GNOME
+use the "freedesktop" or "GNOME" runtimes, which consist of a Yocto base
+system and lots of RPMs, are rebuilt from first principles on-demand,
+and are extensive and capable enough that they make it somewhat non-obvious
+what's in an app or a runtime.
+
+So, here's a step-by-step route through xdg-app, first using typical
+GNOME instructions, but then using the simplest GUI
+app I could find - xvt, a small xterm clone. I'm using a Debian testing
+(stretch) x86\_64 virtual machine for all this. xdg-app currently requires
+systemd-logind to put users and apps in cgroups, either with systemd as
+pid 1 (systemd-sysv) or systemd-shim and cgmanager; I used the default
+systemd-sysv. In principle it could work with plain cgmanager, but nobody
+has contributed that support yet.
+
+### Demonstrating an existing xdg-app
+
+Debian's kernel is currently patched to be able to allow unprivileged users to
+create user namespaces, but make it runtime-configurable, because there have
+been various security issues in that feature, making it a security risk for a
+typical machine (and particularly a server). Hopefully unprivileged user
+namespaces will soon be secure enough that we can enable them by default,
+but for now, we have to do one of three things to let xdg-app use them:
+
+* enable unprivileged user namespaces via sysctl:
+
+      sudo sysctl kernel.unprivileged_userns_clone=1
+
+* make xdg-app root-privileged (it will keep `CAP_SYS_ADMIN` and drop the rest):
+
+      sudo dpkg-statoverride --update --add root root 04755 /usr/bin/xdg-app-helper
+
+* make xdg-app slightly less privileged:
+
+      sudo setcap cap_sys_admin+ep /usr/bin/xdg-app-helper
+
+First, we'll need a runtime. The standard xdg-app tutorial would tell you to
+download the "GNOME Platform" version 3.18. To do that, you'd add a *remote*,
+which is a bit like a git remote, and a bit like an apt repository:
+
+    $ wget http://sdk.gnome.org/keys/gnome-sdk.gpg
+    $ xdg-app remote-add --user --gpg-import=gnome-sdk.gpg gnome \
+        http://sdk.gnome.org/repo/
+
+(I'm ignoring considerations like trust paths and security here, for
+brevity; in real life, you'd want to obtain the signing key via https
+and/or have a trust path to it, just like you would for a secure-apt signing
+key.)
+
+You can list what's available in a remote:
+
+    $ xdg-app remote-ls --user gnome
+    ...
+    org.freedesktop.Platform
+    ...
+    org.freedesktop.Platform.Locale.cy
+    ...
+    org.freedesktop.Sdk
+    ...
+    org.gnome.Platform
+    ...
+
+The Platform runtimes are what we want here: they are collections of
+runtime libraries with which you can run an application. The Sdk runtimes
+add development tools, header files, etc. to be able to compile apps that
+will be compatible with the Platform.
+
+For now, all we want is the GNOME 3.18 platform:
+
+    $ xdg-app install --user gnome org.gnome.Platform 3.18
+
+Next, we can install an app that uses it, from Alex Larsson's nightly
+builds of a subset of GNOME. The server they're on doesn't have a great deal
+of bandwidth, so be nice :-)
+
+    $ wget http://209.132.179.2/keys/nightly.gpg
+    $ xdg-app remote-add --user --gpg-import=nightly.gpg nightly \
+        http://209.132.179.2/repo/
+    $ xdg-app install --user nightly org.mypaint.MypaintDevel
+
+We now have one app, and the runtime it needs:
+

(Diff truncated)
Comment moderation
diff --git a/2015/why_polkit/comment_2_5737545284e3755fe1e923c0bb946c82._comment b/2015/why_polkit/comment_2_5737545284e3755fe1e923c0bb946c82._comment
new file mode 100644
index 0000000..4739a08
--- /dev/null
+++ b/2015/why_polkit/comment_2_5737545284e3755fe1e923c0bb946c82._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="June@fec140941ae43fa8df8c3cfb0ddcf561a27fac76"
+ nickname="June"
+ avatar="http://cdn.libravatar.org/avatar/45d480a40970c748094226fa3174eac3"
+ subject="Great!"
+ date="2015-06-18T14:23:45Z"
+ content="""
+Glad to finally see some info written about this. Any chance this will be put into a man page or a texinfo doc or something similar? The #1 objection I have about almost every single free desktop.org project is their utter lack of documentation of how things work. The #2 objection is not religious as you assume, but technical, but I won't tilt against that windmill here.
+"""]]

Discworld Noir
diff --git a/2015/discworldnoir-boxes.jpg b/2015/discworldnoir-boxes.jpg
new file mode 100644
index 0000000..35a6214
Binary files /dev/null and b/2015/discworldnoir-boxes.jpg differ
diff --git a/2015/discworldnoir.mdwn b/2015/discworldnoir.mdwn
new file mode 100644
index 0000000..132e632
--- /dev/null
+++ b/2015/discworldnoir.mdwn
@@ -0,0 +1,191 @@
+[[!meta title="Discworld Noir in a Windows 98 virtual machine on Linux"]]
+[[!meta date="2015-11-15T17:19:00+0000"]]
+[[!meta updated="2015-11-15T17:19:00+0000"]]
+[[!meta copyright="Copyright © 2015 Simon McVittie"]]
+[[!tag debian qemu games]]
+
+[Discworld Noir](https://en.wikipedia.org/wiki/Discworld_Noir) was a
+superb adventure game, but is also notoriously unreliable, even in
+Windows on real hardware;
+[using Wine is just not going to work](https://appdb.winehq.org/objectManager.php?sClass=version&iId=2254).
+After many attempts at bringing it back into working order, I've settled
+on an approach that seems to work: now that qemu and libvirt
+have made virtualization and emulation easy, I can run it in a version
+of Windows that was current at the time of its release. Unfortunately,
+Windows 98 doesn't virtualize particularly well either, so this
+still became a relatively extensive
+[yak-shaving](http://projects.csail.mit.edu/gsb/old-archive/gsb-archive/gsb2000-02-11.html)
+exercise.
+
+[[discworldnoir-boxes.jpg]]
+
+These instructions assume that `/srv/virt` is a suitable place to put
+disk images, but you can use anywhere you want.
+
+The emulated PC
+---------------
+
+After some trial and error, it seems to work if I configure
+qemu to emulate the following:
+
+- Fully emulated hardware instead of virtualization (`qemu-system-i386 -no-kvm`)
+- Intel Pentium III
+- Intel i440fx-based motherboard with ACPI
+- Real-time clock in local time
+- No HPET
+- 256 MiB RAM
+- IDE primary master: IDE hard disk (I used 30 GiB, which is massively
+  overkill for this game; qemu can use sparse files so it actually ends
+  up less than 2 GiB on the host system)
+- IDE primary slave, secondary master, secondary slave: three CD-ROM drives
+- PS/2 keyboard and mouse
+- Realtek AC97 sound card
+- Cirrus video card with 16 MiB video RAM
+
+A modern laptop CPU is an order of magnitude faster than what Discworld Noir
+needs, so full emulation isn't a problem, despite being inefficient.
+
+There is deliberately no networking, because Discworld Noir doesn't need it,
+and a 17 year old operating system with no privilege separation is
+very much not safe to use on the modern Internet!
+
+Software needed
+---------------
+
+- Windows 98 installation CD-ROM as a `.iso` file
+  (`cp /dev/cdrom windows98.iso`) - in theory you could also use a
+  real optical drive, but my laptop doesn't usually have one of those.
+  I used the OEM disc, version 4.10.1998 (that's the original Windows 98,
+  not the Second Edition), which came with a long-dead PC, and didn't
+  bother to apply any patches.
+- A Windows 98 license key. Again, I used an OEM key from a past PC.
+- A complete set of Discworld Noir (English) CD-ROMs as `.iso` files.
+  I used the UK "Sold Out Software" budget release, on 3 CDs.
+- [A multi-platform Realtek AC97 audio driver](http://drivers.softpedia.com/get/SOUND-CARD/REALTEK/Realtek-AC97-Audio-Driver-A400.shtml).
+
+Windows 98 installation
+-----------------------
+
+It seems to be easiest to do this bit by running qemu-system-i386 manually:
+
+    qemu-img create -f qcow2 /srv/virt/discworldnoir.qcow2 30G
+    qemu-system-i386 -hda /srv/virt/discworldnoir.qcow2 \
+        -drive media=cdrom,format=raw,file=/srv/virt/windows98.iso \
+        -no-kvm -vga cirrus -m 256 -cpu pentium3 -localtime
+
+Don't start the installation immediately. Instead, boot the installation
+CD to a DOS prompt with CD-ROM support. From here, run
+
+    fdisk
+
+and create a single partition filling the emulated hard disk. When
+finished, hard-reboot the virtual machine (press Ctrl+C on the
+`qemu-system-i386` process and run it again).
+
+The DOS `FORMAT.COM` utility is on the Windows CD-ROM but not in the root
+directory or the default `%PATH%`, so you'll have to run:
+
+    d:\win98\format c:
+
+to create the FAT filesystem. You might have to reboot again at this point.
+
+The reason for doing this the hard way is that the Windows 98 installer
+doesn't detect qemu as supporting ACPI. You want ACPI support, so that
+Windows will issue `IDLE` instructions from its idle loop, instead of
+occupying a CPU core with a busy-loop. To get that, boot to a DOS
+prompt again, and use:
+
+    setup /p j /iv
+
+`/p j` forces ACPI support
+(Thanks to ["Richard S" on the Virtualbox forums](https://forums.virtualbox.org/viewtopic.php?f=6&t=32989)
+for this tip.)
+`/iv` is unimportant, but it disables the annoying "billboards" during
+installation, which advertised once-exciting features like support for
+dial-up modems and JPEG wallpaper.
+
+I used a "Typical" installation; there didn't seem to be much point in
+tweaking the installed package set when everything is so small by
+modern standards.
+
+Windows 98 has built-in support for the Cirrus VGA card that we're
+emulating, so after a few reboots, it should be able to run in a
+semi-modern resolution and colour depth. Discworld Noir
+apparently prefers a 640 × 480 × 16-bit video mode, so right-click
+on the desktop background, choose Properties and set that up.
+
+Audio drivers
+-------------
+
+This is the part that took me the longest to get working. Of the sound
+cards that qemu can emulate, Windows 98 only supports the SoundBlaster 16
+out of the box. Unfortunately, [the Soundblaster 16 emulation in qemu is
+incomplete](https://bugs.launchpad.net/qemu/+bug/1295587),
+and in particular version 2.1 (as shipped in Debian 8) has a tendency to
+make Windows lock up during boot.
+
+I've seen advice in various places to emulate an Eqsonic ES1370
+(SoundBlaster AWE 64), but that didn't work for me: one of the drivers I
+tried caused Windows to lock up at a black screen during boot, and the other
+didn't detect the emulated hardware.
+
+The next-oldest sound card that qemu can emulate is a Realtek AC97,
+which was often found integrated into motherboards in the late 1990s.
+This one seems to work, with the "A400" driver bundle linked above.
+For Windows 98 first edition, you need a driver bundle that includes
+the old "VXD" drivers, not just the "WDM" drivers supported by
+Second Edition and newer.
+
+The easiest way to get that into qemu seems to be to turn it into a CD image:
+
+    genisoimage -o /srv/virt/discworldnoir-drivers.iso WDM_A400.exe
+    qemu-system-i386 -hda /srv/virt/discworldnoir.qcow2 \
+        -drive media=cdrom,format=raw,file=/srv/virt/windows98.iso \
+        -drive media=cdrom,format=raw,file=/srv/virt/discworldnoir-drivers.iso \
+        -no-kvm -vga cirrus -m 256 -cpu pentium3 -localtime -soundhw ac97
+
+Run the installer from E:, then reboot with the Windows 98 CD inserted, and
+Windows should install the driver.
+
+Installing Discworld Noir
+-------------------------
+
+Boot up the virtual machine with CD 1 in the emulated drive:
+
+    qemu-system-i386 -hda /srv/virt/discworldnoir.qcow2 \
+        -drive media=cdrom,format=raw,file=/srv/virt/DWN_ENG_1.iso \
+        -no-kvm -vga cirrus -m 256 -cpu pentium3 -localtime -soundhw ac97
+
+You might be thinking "... why not insert all three CDs into D:, E: and F:?"
+but the installer expects subsequent disks to appear in the same drive
+where CD 1 was initially, so that won't work. Instead, when prompted for
+a new CD, switch to the qemu monitor with Ctrl+Alt+2 (note that this
+is 2, _not_ F2). At the `(qemu)` prompt,
+use `info block` to see a list of emulated drives, then issue a
+command like
+
+    change ide0-cd1 /srv/virt/DWN_ENG_2.iso
+
+to swap the CD. Then switch back to Windows' console with Ctrl+Alt+1
+and continue installation. I used a Full installation of Discworld Noir.
+
+Transferring the virtual machine to GNOME Boxes
+-----------------------------------------------
+
+Having finished the "control freak" phase of installation, I wanted a
+slightly more user-friendly way to _run_ this game, so I transferred
+the virtual machine to be used by libvirtd, which is the backend for
+both GNOME Boxes and virt-manager:
+
+    virsh create discworldnoir.xml
+
+[[Here is the configuration I used|discworldnoir.xml]]. It's a mixture
+of automatic configuration from virt-manager, and hand-edited configuration
+to make it match the qemu-system-i386 command-line.
+
+Running the game
+----------------
+
+If all goes well, you should now see a `discworldnoir` virtual machine
+in GNOME Boxes, in which you can boot Windows 98 and play the game.

(Diff truncated)
Comment moderation
diff --git a/2015/why_polkit/comment_1_26e6fab68b3e762d135e35311fd2df19._comment b/2015/why_polkit/comment_1_26e6fab68b3e762d135e35311fd2df19._comment
new file mode 100644
index 0000000..9be186a
--- /dev/null
+++ b/2015/why_polkit/comment_1_26e6fab68b3e762d135e35311fd2df19._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="https://albertodebian.wordpress.com/"
+ nickname="albertodebian"
+ avatar="http://cdn.libravatar.org/avatar/13ffc7c31e719eb6b1ba6b91cb6eff6a"
+ subject="very informative"
+ date="2015-06-05T19:35:18Z"
+ content="""
+thanks! more posts like this one!!
+
+usually the people who better understand it is the people who less need have for documentation and so dont bother... but this was great!
+
+next one on how to debug it! 
+"""]]

try again
diff --git a/2015/why_polkit.mdwn b/2015/why_polkit.mdwn
index c2c6c40..b3f304a 100644
--- a/2015/why_polkit.mdwn
+++ b/2015/why_polkit.mdwn
@@ -214,8 +214,7 @@ a particular disk is in. So `udisks2` can make a more informed decision.
 So, a naive approach might be to write a function in `udisks2` that looks
 something like this pseudocode:
 
-[!format txt """
-may_i_mount_this_disk (user, disk, mount options) → boolean
+[[!format txt """may_i_mount_this_disk (user, disk, mount options) → boolean
 {
     if (user is root || user is root-equivalent)
         return true;
@@ -238,8 +237,7 @@ may_i_mount_this_disk (user, disk, mount options) → boolean
        return false;
 
     return true;
-}
-"""]]
+}"""]]
 
 ## Delegating the security policy to something central
 

fix
diff --git a/2015/why_polkit.mdwn b/2015/why_polkit.mdwn
index ae6eb83..c2c6c40 100644
--- a/2015/why_polkit.mdwn
+++ b/2015/why_polkit.mdwn
@@ -214,7 +214,8 @@ a particular disk is in. So `udisks2` can make a more informed decision.
 So, a naive approach might be to write a function in `udisks2` that looks
 something like this pseudocode:
 
-[!format txt """may_i_mount_this_disk (user, disk, mount options) → boolean
+[!format txt """
+may_i_mount_this_disk (user, disk, mount options) → boolean
 {
     if (user is root || user is root-equivalent)
         return true;

better formatting
diff --git a/2015/why_polkit.mdwn b/2015/why_polkit.mdwn
index 87188d9..ae6eb83 100644
--- a/2015/why_polkit.mdwn
+++ b/2015/why_polkit.mdwn
@@ -214,8 +214,7 @@ a particular disk is in. So `udisks2` can make a more informed decision.
 So, a naive approach might be to write a function in `udisks2` that looks
 something like this pseudocode:
 
-<pre><code>[[!format txt """
-may_i_mount_this_disk (user, disk, mount options) -> boolean
+[!format txt """may_i_mount_this_disk (user, disk, mount options) → boolean
 {
     if (user is root || user is root-equivalent)
         return true;
@@ -239,7 +238,7 @@ may_i_mount_this_disk (user, disk, mount options) -> boolean
 
     return true;
 }
-"""]]</code></pre>
+"""]]
 
 ## Delegating the security policy to something central
 

use format txt so the link works
diff --git a/2015/why_polkit.mdwn b/2015/why_polkit.mdwn
index f403839..87188d9 100644
--- a/2015/why_polkit.mdwn
+++ b/2015/why_polkit.mdwn
@@ -214,30 +214,32 @@ a particular disk is in. So `udisks2` can make a more informed decision.
 So, a naive approach might be to write a function in `udisks2` that looks
 something like this pseudocode:
 
-    may_i_mount_this_disk (user, disk, mount options) -> boolean
-    {
-        if (user is root || user is root-equivalent)
-            return true;
+<pre><code>[[!format txt """
+may_i_mount_this_disk (user, disk, mount options) -> boolean
+{
+    if (user is root || user is root-equivalent)
+        return true;
 
-        if (disk is not removable)
-           return false;
+    if (disk is not removable)
+       return false;
 
-        if (mount options are scary)
-           return false;
+    if (mount options are scary)
+       return false;
 
-        if (user is in “manipulate non-local disks” group)
-            return true;
+    if (user is in “manipulate non-local disks” group)
+        return true;
 
-        if (user is not logged-in locally)
-           return false;
+    if (user is not logged-in locally)
+       return false;
 
-        # [[https://en.wikipedia.org/wiki/Multiseat_configuration]]
-        if (user is not logged-in on the same seat where the disk is
-                plugged in)
-           return false;
+    # [[https://en.wikipedia.org/wiki/Multiseat_configuration]]
+    if (user is not logged-in on the same seat where the disk is
+            plugged in)
+       return false;
 
-        return true;
-    }
+    return true;
+}
+"""]]</code></pre>
 
 ## Delegating the security policy to something central
 

more tags
diff --git a/2015/why_polkit.mdwn b/2015/why_polkit.mdwn
index 08974e4..f403839 100644
--- a/2015/why_polkit.mdwn
+++ b/2015/why_polkit.mdwn
@@ -2,7 +2,7 @@
 [[!meta date="2015-06-05T17:32:30+0100"]]
 [[!meta updated="2015-06-05T17:32:30+0100"]]
 [[!meta copyright="Copyright © 2015 Collabora Ltd."]]
-[[!tag debian]]
+[[!tag debian polkit d-bus udisks]]
 
 I've recently found myself explaining `polkit` (formerly PolicyKit) to one of
 [Collabora](https://www.collabora.com/)'s clients, and thought that

Why polkit (or, how to mount a disk on modern Linux)
diff --git a/2014/still_universal.mdwn b/2014/still_universal.mdwn
index e4f0a90..835ba2b 100644
--- a/2014/still_universal.mdwn
+++ b/2014/still_universal.mdwn
@@ -1,6 +1,6 @@
 [[!meta title="still aiming to be the universal operating system"]]
-[[!meta date="2014-11-19"]]
-[[!meta updated="2014-11-19"]]
+[[!meta date="2014-11-19T23:59+0000"]]
+[[!meta updated="2014-11-19T23:59+0000"]]
 [[!meta copyright="Copyright © 2014 Simon McVittie"]]
 [[!tag debian]]
 
diff --git a/2015.mdwn b/2015.mdwn
new file mode 100644
index 0000000..c419b5d
--- /dev/null
+++ b/2015.mdwn
@@ -0,0 +1 @@
+[[!map pages="2015/* and copyright(*)" show=title]]
diff --git a/2015/why_polkit.mdwn b/2015/why_polkit.mdwn
new file mode 100644
index 0000000..08974e4
--- /dev/null
+++ b/2015/why_polkit.mdwn
@@ -0,0 +1,345 @@
+[[!meta title="Why polkit (or, how to mount a disk on modern Linux)"]]
+[[!meta date="2015-06-05T17:32:30+0100"]]
+[[!meta updated="2015-06-05T17:32:30+0100"]]
+[[!meta copyright="Copyright © 2015 Collabora Ltd."]]
+[[!tag debian]]
+
+I've recently found myself explaining `polkit` (formerly PolicyKit) to one of
+[Collabora](https://www.collabora.com/)'s clients, and thought that
+blogging about the same topic might be useful for
+[other people who are confused by it](http://changelog.complete.org/archives/9299-has-modern-linux-lost-its-way-some-thoughts-on-jessie);
+so, here is why `udisks2` and `polkit` are the way they are.
+
+As always, opinions in this blog are my own, not Collabora's.
+
+## Privileged actions
+
+Broadly, there are two ways a process can do something: it can do it
+directly (i.e. ask the kernel directly), or it can use inter-process
+communication to ask a service to do that operation on its behalf.
+If it does it directly, the components that say whether it can succeed
+are the Linux kernel's normal permissions checks
+([DAC](https://en.wikipedia.org/wiki/Discretionary_access_control)),
+and if configured, AppArmor, SELinux or a similar
+[MAC](https://en.wikipedia.org/wiki/Mandatory_access_control) layer.
+All very simple so far.
+
+Unfortunately, the kernel's relatively coarse-grained checks are not sufficient
+to express the sorts of policies that exist on a desktop/laptop/mobile
+system. My favourite example for this sort of thing is mounting filesystems.
+If I plug in a USB stick with a FAT filesystem, it's reasonable to expect
+my chosen user interface to either mount it automatically, or
+let me press a button to mount it. Similarly, to avoid data loss, I
+should be able to unmount it when I'm finished with it.
+However, mounting and unmounting a USB stick is fundamentally the same
+system call as mounting and unmounting any other filesystem - and if
+ordinary users can do arbitrary mount system calls, they can cause all
+sorts of chaos, for instance by mounting a filesystem that contains setuid
+executables (privilege escalation), or umounting a critical OS filesystem
+like `/usr` (denial of service). Something needs to arbitrate: “you can mount
+filesystems, but only under certain conditions”.
+
+The kernel developer motto for this sort of thing is “mechanism, not policy”:
+they are very keen to avoid encoding particular environments' policies
+(the sort of thing you could think of as “business rules”) in the kernel,
+because that makes it non-generic and hard to maintain. As a result,
+direct mount/unmount actions are only allowed by privileged processes,
+and it's up to user-space processes to arrange for a privileged process
+to make the desired mount syscall.
+
+Here are some other privileged actions which laptop/desktop users can
+reasonably expect to “just work”, with or without requiring a sysadmin-like
+(root-equivalent) user:
+
+* reconfiguring networking (privileged because, in the general case, it's an
+  availability and potentially integrity issue)
+* installing, upgrading or removing packages (privileged because, in the
+  general case, it can result in arbitrary root code execution)
+* suspending or shutting down the system (privileged because you wouldn't
+  want random people doing this on your server, but should normally be
+  allowed on e.g. laptops for people with physical access, because they could
+  just disconnect the power anyway)
+
+In environments that use a MAC framework like AppArmor, actions that
+would normally be allowed can become privileged: for instance, in a
+framework for sandboxed applications, most apps shouldn't be allowed to
+record audio. This prevents carrying out these actions directly,
+again resulting in the only way to achieve them being to ask a service
+to carry out the action.
+
+## Ask a system service to do it
+
+On to the next design, then: I can submit a request to a privileged process,
+which does some checks to make sure I'm not trying to break the system
+(or alternatively, that I have enough sysadmin rights that I'm allowed
+to break the system if I want to), and then does the privileged
+action for me.
+
+You might think I'm about to start discussing D-Bus and daemons, but
+actually, a prominent earlier implementation of this was mount(8), which
+is normally setuid root:
+
+    % ls -l /bin/mount
+    -rwsr-xr-x 1 root root 40000 May 22 11:37 /bin/mount
+
+If you look at it from an odd angle, this is inter-process communication
+across a privilege boundary: I run the setuid executable, creating a
+process. Because the executable has the setuid bit set, the kernel makes
+the process highly privileged: its effective uid is root, and it has
+all the necessary capabilities to mount filesystems. I submit the request
+by passing it in the command-line arguments. mount does some checks -
+specifically, it looks in `/etc/fstab` to see whether the filesystem I'm
+trying to mount has the “`user`” or “`users`” flag - then carries out the
+mount system call.
+
+There are a few obvious problems with this:
+
+* When machines had
+  [a static set of hardware devices](https://www.redhat.com/archives/redhat-install-list/2003-July/msg00199.html)
+  (and a sysadmin who knew how to configure them), it might have
+  made sense to list them all in /etc/fstab; but this is not a useful
+  solution if you can plug in any number of USB drives, or if you are
+  a non-expert user with Linux on your laptop. The decision
+  ought to be based on general attributes of devices, such as “is removable?”,
+  and on the role of the machine.
+* Setuid executables are
+  [alarmingly easy to get wrong](http://www.dwheeler.com/secure-class/Secure-Programs-HOWTO/environment-variables.html)
+  so it is [not](https://security-tracker.debian.org/tracker/CVE-2013-0157)
+  [necessarily](https://security-tracker.debian.org/tracker/CVE-2007-5191)
+  [wise](https://security-tracker.debian.org/tracker/CVE-2005-2876)
+  to assume that mount(8) is safe to be setuid.
+* One fact that a reasonable security policy might include is “users who
+  are logged in remotely should have less control over physically present
+  devices than those who are physically present” - but that sort of thing
+  can't be checked by mount(8) without specifically teaching the
+  mount binary about it.
+
+### Ask a system service to do it, via D-Bus or other IPC
+
+To avoid the issues of setuid, we could use inter-process communication in
+the traditional sense: run a privileged daemon (on boot or on-demand),
+make it listen for requests, and use the IPC channel as our privilege boundary.
+
+`udisks2` is one such privileged daemon, which uses D-Bus as its IPC channel.
+D-Bus is a commonly-used inter-process system; one of its
+intended/designed uses is to let user processes and system services
+communicate, especially this sort of communication between a privileged
+daemon and its less-privileged clients.
+
+People sometimes criticize D-Bus as not doing anything you couldn't do yourself
+with some `AF_UNIX` sockets. Well, no, of course it doesn't - the important
+bit of the reference implementation and the various interoperable
+reimplementations consists of a daemon and some `AF_UNIX` sockets, and the
+rest is
+[a simple matter of programming](https://en.wikipedia.org/wiki/Small_matter_of_programming).
+However, it's sufficient for most uses in its problem space, and is usually better than inventing your
+own.
+
+The advantage of D-Bus over doing your own thing is precisely that you
+are not doing your own thing: good IPC design is hard, and D-Bus makes
+some structural decisions so that fewer application
+authors have to think about them. For instance, it has a central “hub” daemon
+(the `dbus-daemon`, or “message bus”) so that <i>n</i> communicating applications
+don't need O(<i>n</i>²) sockets; it uses the `dbus-daemon` to provide a
+[total message ordering](https://en.wikipedia.org/wiki/Total_order)
+so you don't have to think about message reordering; it has a distributed
+naming model (which can also be used as a distributed mutex) so you don't
+have to design that; it has a serialization format and a type system so you
+don't have to design one of those; it has a framework for “activating"
+run-on-demand daemons so they don't have to use resources initially,
+implemented using a setuid helper and/or systemd; and so on.
+
+If you have religious objections to D-Bus, you can mentally replace
+“D-Bus” with “`AF_UNIX` or something” and most of this article will
+still be true.
+
+## Is this OK?
+
+In either case - `exec`'ing a privileged helper, or submitting a request to a
+privileged daemon via IPC - the privileged process has two questions that
+it needs to answer before it does its work:
+
+* what am I being asked to do?
+* should I do it?
+
+It needs to make some sort of decision on the latter based on the
+information available to it. However, before we even get there, there is
+another layer:
+
+* did the request get there at all?
+
+In the setuid model, there is a simple security check that you can
+apply: you can make `/bin/mount` only executable by a particular group,
+or only executable by certain AppArmor profiles, or similar. That works
+up to a point, but cannot distinguish between physically-present and

(Diff truncated)
blog post
diff --git a/2014.mdwn b/2014.mdwn
new file mode 100644
index 0000000..10512f2
--- /dev/null
+++ b/2014.mdwn
@@ -0,0 +1 @@
+[[!map pages="2014/* and copyright(*)" show=title]]
diff --git a/2014/still_universal.mdwn b/2014/still_universal.mdwn
new file mode 100644
index 0000000..e4f0a90
--- /dev/null
+++ b/2014/still_universal.mdwn
@@ -0,0 +1,70 @@
+[[!meta title="still aiming to be the universal operating system"]]
+[[!meta date="2014-11-19"]]
+[[!meta updated="2014-11-19"]]
+[[!meta copyright="Copyright © 2014 Simon McVittie"]]
+[[!tag debian]]
+
+Debian's latest round of angry mailing list threads have been about some
+combination of init systems, future direction and project governance.
+The details aren't particularly important here, and pretty much everything
+worthwhile in favour of or against each position has already been said several
+times, but I think this bit is important enough that it bears repeating:
+the reason I voted "we didn't need this General Resolution" ahead
+of the other options is that I hope we can continue to use our normal
+technical and decision-making processes to make Debian 8 the best possible
+OS distribution for everyone. That includes people who like systemd,
+people who dislike systemd, people who don't care either way and just
+want the OS to work, and everyone in between those extremes.
+
+I think that works best when we do things, and least well when a lot
+of time and energy get diverted into talking about doing things.
+I've been trying to do my small part of the former by
+[fixing some release-critical bugs](https://udd.debian.org/bugs.cgi) so we
+can release Debian 8. Please join in, and remember to
+[write](http://www.jwiltshire.org.uk/content/2014/11/16/getting-things-into-jessie-1/)
+[good](http://www.jwiltshire.org.uk/content/2014/11/17/getting-things-into-jessie-2/)
+[unblock](http://www.jwiltshire.org.uk/content/2014/11/18/getting-things-into-jessie-3/)
+[requests](http://www.jwiltshire.org.uk/content/2014/11/19/getting-things-into-jessie-4/)
+so our hard-working release team can get through them in a finite time.
+I realise not everyone will agree with my idea of which bugs, which
+features and which combinations of packages are
+highest-priority; that's fine, there are plenty of bugs to go round!
+
+Regarding init systems specifically, Debian 'jessie' currently works with
+at least systemd-sysv or sysvinit-core as pid 1 (probably also Upstart, but
+I haven't tried that) and I'm confident that Debian developers won't let
+either of those regress before it's released as Debian 8.
+
+I expect the freeze for Debian 'stretch' (presumably Debian 9) to be a
+couple of years away, so it seems premature to say anything about what
+will or won't be supported there; that depends on what upstream developers
+do, and what Debian developers do, between now and then. What I can predict is
+that the components that get
+[useful bug reports](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html),
+active maintenance, thorough testing, careful review,
+and similar help from contributors will work better than the things
+that don't; so if you like a component and want it to be supported in
+Debian, you can help by, well, supporting it.
+
+----
+
+PS. If you want the Debian 8 installer to leave you running sysvinit
+as pid 1 after the first reboot, here's a suitable incantation to add to
+the kernel command-line in the installer's bootloader. This one certainly
+worked when [KiBi](http://mraw.org/blog/) asked for testing a few days ago:
+
+    preseed/late_command="in-target apt-get install -y sysvinit-core"
+
+I think that corresponds to this line in a preseeding file, if you use those:
+
+    d-i preseed/late_command string in-target apt-get install -y sysvinit-core
+
+A similar apt-get command, without the in-target prefix, should work on an
+installed system that already has systemd-sysv. Depending on other installed
+software, you might need to add systemd-shim to the command line too,
+but when I tried it, apt-get was able to work that out for itself.
+
+If you use aptitude instead of apt-get, double-check what it will do
+before saying "yes" to this particular switchover: its heuristic for
+resolving conflicts seems to be rather more trigger-happy about removing
+packages than the one in apt-get.

use the merged version of the trail plugin
diff --git a/local.css b/local.css
index e57e876..c31f65b 100644
--- a/local.css
+++ b/local.css
@@ -1,2 +1 @@
 @import url("/style/pcu.css");
-@import url("/style/trail.css");
diff --git a/templates/page.tmpl b/templates/page.tmpl
deleted file mode 100644
index 770ac23..0000000
--- a/templates/page.tmpl
+++ /dev/null
@@ -1,207 +0,0 @@
-<TMPL_IF HTML5><!DOCTYPE html>
-<html>
-<TMPL_ELSE><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-</TMPL_IF>
-<head>
-<TMPL_IF DYNAMIC>
-<TMPL_IF FORCEBASEURL><base href="<TMPL_VAR FORCEBASEURL>" /><TMPL_ELSE>
-<TMPL_IF BASEURL><base href="<TMPL_VAR BASEURL>" /></TMPL_IF>
-</TMPL_IF>
-</TMPL_IF>
-<TMPL_IF HTML5><meta charset="utf-8" /><TMPL_ELSE><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></TMPL_IF>
-<title><TMPL_VAR TITLE></title>
-<TMPL_IF FAVICON>
-<link rel="icon" href="<TMPL_VAR BASEURL><TMPL_VAR FAVICON>" type="image/x-icon" />
-</TMPL_IF>
-<link rel="stylesheet" href="<TMPL_VAR BASEURL>style.css" type="text/css" />
-<TMPL_IF LOCAL_CSS>
-<link rel="stylesheet" href="<TMPL_VAR BASEURL><TMPL_VAR LOCAL_CSS>" type="text/css" />
-<TMPL_ELSE>
-<link rel="stylesheet" href="<TMPL_VAR BASEURL>local.css" type="text/css" />
-</TMPL_IF>
-<TMPL_IF EDITURL>
-<link rel="alternate" type="application/x-wiki" title="Edit this page" href="<TMPL_VAR EDITURL>" />
-</TMPL_IF>
-<TMPL_IF FEEDLINKS><TMPL_VAR FEEDLINKS></TMPL_IF>
-<TMPL_IF RELVCS><TMPL_VAR RELVCS></TMPL_IF>
-<TMPL_IF META><TMPL_VAR META></TMPL_IF>
-<TMPL_LOOP TRAILLOOP>
-<TMPL_IF PREVPAGE>
-<link rel="prev" href="<TMPL_VAR PREVURL>" title="<TMPL_VAR PREVTITLE>" />
-</TMPL_IF>
-<link rel="up" href="<TMPL_VAR TRAILURL>" title="<TMPL_VAR TRAILTITLE>" />
-<TMPL_IF NEXTPAGE>
-<link rel="next" href="<TMPL_VAR NEXTURL>" title="<TMPL_VAR NEXTTITLE>" />
-</TMPL_IF>
-</TMPL_LOOP>
-</head>
-<body>
-
-<TMPL_IF HTML5><article class="page"><TMPL_ELSE><div class="page"></TMPL_IF>
-
-<TMPL_IF HTML5><section class="pageheader"><TMPL_ELSE><div class="pageheader"></TMPL_IF>
-<TMPL_IF HTML5><header class="header"><TMPL_ELSE><div class="header"></TMPL_IF>
-<span>
-<span class="parentlinks">
-<TMPL_LOOP PARENTLINKS>
-<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>/ 
-</TMPL_LOOP>
-</span>
-<span class="title">
-<TMPL_VAR TITLE>
-<TMPL_IF ISTRANSLATION>
-&nbsp;(<TMPL_VAR PERCENTTRANSLATED>%)
-</TMPL_IF>
-</span>
-</span>
-<TMPL_IF SEARCHFORM>
-<TMPL_VAR SEARCHFORM>
-</TMPL_IF>
-<TMPL_IF HTML5></header><TMPL_ELSE></div></TMPL_IF>
-
-<TMPL_IF HAVE_ACTIONS>
-<TMPL_IF HTML5><nav class="actions"><TMPL_ELSE><div class="actions"></TMPL_IF>
-<ul>
-<TMPL_IF EDITURL>
-<li><a href="<TMPL_VAR EDITURL>" rel="nofollow">Edit</a></li>
-</TMPL_IF>
-<TMPL_IF RECENTCHANGESURL>
-<li><a href="<TMPL_VAR RECENTCHANGESURL>">RecentChanges</a></li>
-</TMPL_IF>
-<TMPL_IF HISTORYURL>
-<li><a href="<TMPL_VAR HISTORYURL>">History</a></li>
-</TMPL_IF>
-<TMPL_IF GETSOURCEURL>
-<li><a href="<TMPL_VAR GETSOURCEURL>">Source</a></li>
-</TMPL_IF>
-<TMPL_IF PREFSURL>
-<li><a href="<TMPL_VAR PREFSURL>">Preferences</a></li>
-</TMPL_IF>
-<TMPL_IF ACTIONS>
-<TMPL_LOOP ACTIONS>
-<li><TMPL_VAR ACTION></li>
-</TMPL_LOOP>
-</TMPL_IF>
-<TMPL_IF COMMENTSLINK>
-<li><TMPL_VAR COMMENTSLINK></li>
-<TMPL_ELSE>
-<TMPL_IF DISCUSSIONLINK>
-<li><TMPL_VAR DISCUSSIONLINK></li>
-</TMPL_IF>
-</TMPL_IF>
-</ul>
-<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
-</TMPL_IF>
-
-<TMPL_IF OTHERLANGUAGES>
-<TMPL_IF HTML5><nav id="otherlanguages"><TMPL_ELSE><div id="otherlanguages"></TMPL_IF>
-<ul>
-<TMPL_LOOP OTHERLANGUAGES>
-<li>
-<a href="<TMPL_VAR URL>"><TMPL_VAR LANGUAGE></a>
-<TMPL_IF MASTER>
-(master)
-<TMPL_ELSE>
-&nbsp;(<TMPL_VAR PERCENT>%)
-</TMPL_IF>
-</li>
-</TMPL_LOOP>
-</ul>
-<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
-</TMPL_IF>
-
-<TMPL_VAR TRAILS>
-
-<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
-
-<TMPL_IF SIDEBAR>
-<TMPL_IF HTML5><aside class="sidebar"><TMPL_ELSE><div class="sidebar"></TMPL_IF>
-<TMPL_VAR SIDEBAR>
-<TMPL_IF HTML5></aside><TMPL_ELSE></div></TMPL_IF>
-</TMPL_IF>
-
-<div id="pagebody">
-
-<TMPL_IF HTML5><section id="content"><TMPL_ELSE><div id="content"></TMPL_IF>
-<TMPL_VAR CONTENT>
-<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
-
-<TMPL_UNLESS DYNAMIC>
-<TMPL_IF COMMENTS>
-<TMPL_IF HTML5><section id="comments"><TMPL_ELSE><div id="comments"></TMPL_IF>
-<TMPL_VAR COMMENTS>
-<TMPL_IF ADDCOMMENTURL>
-<div class="addcomment">
-<a href="<TMPL_VAR ADDCOMMENTURL>">Add a comment</a>
-</div>
-<TMPL_ELSE>
-<div class="addcomment">Comments on this page are closed.</div>
-</TMPL_IF>
-<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
-</TMPL_IF>
-</TMPL_UNLESS>
-
-</div>
-
-<TMPL_IF HTML5><footer id="footer" class="pagefooter"><TMPL_ELSE><div id="footer" class="pagefooter"></TMPL_IF>
-<TMPL_UNLESS DYNAMIC>
-<TMPL_IF HTML5><nav id="pageinfo"><TMPL_ELSE><div id="pageinfo"></TMPL_IF>
-
-<TMPL_IF TAGS>
-<TMPL_IF HTML5><nav class="tags"><TMPL_ELSE><div class="tags"></TMPL_IF>
-Tags:
-<TMPL_LOOP TAGS>
-<TMPL_VAR LINK>
-</TMPL_LOOP>
-<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
-</TMPL_IF>
-
-<TMPL_IF BACKLINKS>
-<TMPL_IF HTML5><nav id="backlinks"><TMPL_ELSE><div id="backlinks"></TMPL_IF>
-Links:
-<TMPL_LOOP BACKLINKS>
-<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>
-</TMPL_LOOP>
-<TMPL_IF MORE_BACKLINKS>
-<span class="popup">...
-<span class="balloon">
-<TMPL_LOOP MORE_BACKLINKS>
-<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>
-</TMPL_LOOP>
-</span>
-</span>
-</TMPL_IF>
-<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
-</TMPL_IF>
-
-<TMPL_IF COPYRIGHT>
-<div class="pagecopyright">
-<a name="pagecopyright"></a>
-<TMPL_VAR COPYRIGHT>
-</div>
-</TMPL_IF>
-
-<TMPL_IF LICENSE>
-<div class="pagelicense">

(Diff truncated)
Comment moderation
diff --git a/2008/08/collaboratively/comment_1_a84b93620c75ccd319d40db3369491d8._comment b/2008/08/collaboratively/comment_1_a84b93620c75ccd319d40db3369491d8._comment
new file mode 100644
index 0000000..b6a4d56
--- /dev/null
+++ b/2008/08/collaboratively/comment_1_a84b93620c75ccd319d40db3369491d8._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="http://joel.rosdahl.net/"
+ nickname="jrosdahl"
+ subject="A better way"
+ date="2011-12-11T20:17:39Z"
+ content="""
+A both easier and more robust way of doing it is this:
+
+    export CCACHE_PREFIX=icecc
+
+See <http://ccache.samba.org/manual.html#_using_ccache_with_other_compiler_wrappers>.
+"""]]

use inline with trail, not trailinline
diff --git a/index.mdwn b/index.mdwn
index 99f30ab..95debaf 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -10,8 +10,8 @@
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
-[[!trailinline pages="20*/* and copyright(*) and !*/Discussion"
-  show="5" actions="yes" sort="age"
+[[!inline pages="20*/* and copyright(*) and !*/Discussion"
+  show="5" actions="yes" sort="age" trail="yes"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]
 

Merge remote-tracking branch 'staging/master' and delete trail.css
Conflicts:
style/trail.css
rely on IkiWiki really having a trail plugin
diff --git a/style/trail.css b/style/trail.css
index 1bd1862..0fdc145 100644
--- a/style/trail.css
+++ b/style/trail.css
@@ -1,40 +1 @@
-/* from IkiWiki branch */
-
-.trail {
-	display: block;
-	clear: both;
-	position: relative;
-}
-
-.trailprev {
-	display: block;
-	text-align: left;
-	position: absolute;
-	top: 0%;
-	left: 3%;
-	width: 30%;
-}
-
-.trailup {
-	display: block;
-	text-align: center;
-	margin-left: 35%;
-	margin-right: 35%;
-}
-
-.trailnext {
-	display: block;
-	text-align: right;
-	position: absolute;
-	top: 0%;
-	width: 30%;
-	right: 3%;
-}
-
-.trailsep {
-	display: none;
-}
-
-/* pseudorandom-specific */
-
 .trails, .actions { margin-top: 0.5em; margin-bottom: 0.5em; }

even more margin
diff --git a/style/trail.css b/style/trail.css
index e6a08ed..1bd1862 100644
--- a/style/trail.css
+++ b/style/trail.css
@@ -37,4 +37,4 @@
 
 /* pseudorandom-specific */
 
-.trails, .actions { margin-top: 0.2em; margin-bottom: 0.2em; }
+.trails, .actions { margin-top: 0.5em; margin-bottom: 0.5em; }

more margin
diff --git a/style/trail.css b/style/trail.css
index 6b26540..e6a08ed 100644
--- a/style/trail.css
+++ b/style/trail.css
@@ -34,3 +34,7 @@
 .trailsep {
 	display: none;
 }
+
+/* pseudorandom-specific */
+
+.trails, .actions { margin-top: 0.2em; margin-bottom: 0.2em; }

more margin
diff --git a/style/trail.css b/style/trail.css
index 6b26540..1bd1862 100644
--- a/style/trail.css
+++ b/style/trail.css
@@ -34,3 +34,7 @@
 .trailsep {
 	display: none;
 }
+
+/* pseudorandom-specific */
+
+.trails, .actions { margin-top: 0.5em; margin-bottom: 0.5em; }

remove generic style
diff --git a/style/trail.css b/style/trail.css
index 35a1331..6b26540 100644
--- a/style/trail.css
+++ b/style/trail.css
@@ -1,506 +1,4 @@
-/* ikiwiki style sheet */
-
-/* Note that instead of modifying this style sheet, you can instead edit
- * local.css and use it to override or change settings in this one.
- */
-
-/* html5 compat */
-article,
-header,
-footer,
-nav {
-	display: block;
-}
-
-.header {
-	margin: 0;
-	font-size: 140%;
-	font-weight: bold;
-	line-height: 1em;
-	display: block;
-}
-
-.inlineheader .author {
-	margin: 0;
-	font-size: 112%;
-	font-weight: bold;
-	display: block;
-}
-
-.actions ul {
-	margin: 0;
-	padding: 6px .4em;
-	height: 1em;
-	list-style-type: none;
-}
-.actions li {
-	display: inline;
-	padding: .2em;
-}
-.pageheader .actions ul {
-	border-bottom: 1px solid #000;
-}
-
-.inlinepage .actions ul {
-	border-bottom: 0;
-}
-
-#otherlanguages ul {
-	margin: 0;
-	padding: 6px;
-	list-style-type: none;
-}
-#otherlanguages li {
-	display: inline;
-	padding: .2em .4em;
-}
-.pageheader #otherlanguages {
-	border-bottom: 1px solid #000;
-}
-
-.inlinecontent {
-	margin-top: .4em;
-}
-
-.pagefooter,
-.inlinefooter,
-.comments {
-	clear: both;
-}
-
-#pageinfo {
-	margin: 1em 0;
-	border-top: 1px solid #000;
-}
-
-.tags {
-	margin-top: 1em;
-}
-
-.inlinepage .tags {
-        display: inline;
-}
-
-.mapparent {
-	text-decoration: none;
-}
-
-.img caption {
-	font-size: 80%;
-	caption-side: bottom;
-	text-align: center;
-}
-
-img.img {
-	margin: 0.5ex;
-}
-
-.align-left {
-	float:left;
-}
-
-.align-right {
-	float:right;
-}
-
-#backlinks {
-	margin-top: 1em;
-}
-
-#searchform {
-	display: inline;
-	float: right;
-}
-
-#editcontent {
-	width: 98%;
-}
-
-.editcontentdiv {
-	width: auto;
-	overflow: auto;
-}
-
-img {
-	border-style: none;
-}
-
-pre {
-	overflow: auto;
-}
-
-div.recentchanges {
-	border-style: solid;
-	border-width: 1px;
-	overflow: auto;
-	width: auto;
-	clear: none;
-	background: #eee;
-	color: black !important;
-}
-.recentchanges .metadata {
-	padding: 0px 0.5em;
-}
-.recentchanges .changelog {
-	font-style: italic;
-	clear: both;
-	display: block;
-	padding: 1px 2px;
-	background: white !important;
-	color: black !important;
-}
-.recentchanges .desc {
-	display: none;
-}
-.recentchanges .diff {
-	display: none;
-}
-.recentchanges .committer {
-	float: left;
-	margin: 0;
-	width: 40%;
-}
-.recentchanges .committype {
-	float: left;
-	margin: 0;
-	width: 5%;
-	font-size: small;
-}
-.recentchanges .changedate {
-	float: left;
-	margin: 0;
-	width: 35%;
-	font-size: small;
-}
-.recentchanges .pagelinks,
-.recentchanges .revert {
-	float: right;
-	margin: 0;
-	width: 60%;
-}
-
-.blogform, #blogform {
-	padding: 10px 10px;
-	border: 1px solid #aaa;
-	background: #eee;
-	color: black !important;
-	width: auto;
-	overflow: auto;
-}
-
-.inlinepage {
-	padding: 10px 10px;
-	border: 1px solid #aaa;
-	overflow: auto;
-}

(Diff truncated)
other way
diff --git a/index.mdwn b/index.mdwn
index cf48691..99f30ab 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -11,7 +11,7 @@ This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
 [[!trailinline pages="20*/* and copyright(*) and !*/Discussion"
-  show="5" actions="yes" sort="-age"
+  show="5" actions="yes" sort="age"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]
 

sort by decreasing age
diff --git a/index.mdwn b/index.mdwn
index c6157e5..cf48691 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -11,7 +11,7 @@ This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
 [[!trailinline pages="20*/* and copyright(*) and !*/Discussion"
-  show="5" actions="yes"
+  show="5" actions="yes" sort="-age"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]
 

use a trail
diff --git a/index.mdwn b/index.mdwn
index 24fc35c..99f30ab 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -10,8 +10,8 @@
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
-[[!inline pages="20*/* and copyright(*) and !*/Discussion"
-  show="5" actions="yes"
+[[!trailinline pages="20*/* and copyright(*) and !*/Discussion"
+  show="5" actions="yes" sort="age"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]
 

use a trail
diff --git a/index.mdwn b/index.mdwn
index 24fc35c..c6157e5 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -10,7 +10,7 @@
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
-[[!inline pages="20*/* and copyright(*) and !*/Discussion"
+[[!trailinline pages="20*/* and copyright(*) and !*/Discussion"
   show="5" actions="yes"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]

add resource files for my ikiwiki trail plugin
diff --git a/local.css b/local.css
new file mode 100644
index 0000000..e57e876
--- /dev/null
+++ b/local.css
@@ -0,0 +1,2 @@
+@import url("/style/pcu.css");
+@import url("/style/trail.css");
diff --git a/style/trail.css b/style/trail.css
new file mode 100644
index 0000000..35a1331
--- /dev/null
+++ b/style/trail.css
@@ -0,0 +1,538 @@
+/* ikiwiki style sheet */
+
+/* Note that instead of modifying this style sheet, you can instead edit
+ * local.css and use it to override or change settings in this one.
+ */
+
+/* html5 compat */
+article,
+header,
+footer,
+nav {
+	display: block;
+}
+
+.header {
+	margin: 0;
+	font-size: 140%;
+	font-weight: bold;
+	line-height: 1em;
+	display: block;
+}
+
+.inlineheader .author {
+	margin: 0;
+	font-size: 112%;
+	font-weight: bold;
+	display: block;
+}
+
+.actions ul {
+	margin: 0;
+	padding: 6px .4em;
+	height: 1em;
+	list-style-type: none;
+}
+.actions li {
+	display: inline;
+	padding: .2em;
+}
+.pageheader .actions ul {
+	border-bottom: 1px solid #000;
+}
+
+.inlinepage .actions ul {
+	border-bottom: 0;
+}
+
+#otherlanguages ul {
+	margin: 0;
+	padding: 6px;
+	list-style-type: none;
+}
+#otherlanguages li {
+	display: inline;
+	padding: .2em .4em;
+}
+.pageheader #otherlanguages {
+	border-bottom: 1px solid #000;
+}
+
+.inlinecontent {
+	margin-top: .4em;
+}
+
+.pagefooter,
+.inlinefooter,
+.comments {
+	clear: both;
+}
+
+#pageinfo {
+	margin: 1em 0;
+	border-top: 1px solid #000;
+}
+
+.tags {
+	margin-top: 1em;
+}
+
+.inlinepage .tags {
+        display: inline;
+}
+
+.mapparent {
+	text-decoration: none;
+}
+
+.img caption {
+	font-size: 80%;
+	caption-side: bottom;
+	text-align: center;
+}
+
+img.img {
+	margin: 0.5ex;
+}
+
+.align-left {
+	float:left;
+}
+
+.align-right {
+	float:right;
+}
+
+#backlinks {
+	margin-top: 1em;
+}
+
+#searchform {
+	display: inline;
+	float: right;
+}
+
+#editcontent {
+	width: 98%;
+}
+
+.editcontentdiv {
+	width: auto;
+	overflow: auto;
+}
+
+img {
+	border-style: none;
+}
+
+pre {
+	overflow: auto;
+}
+
+div.recentchanges {
+	border-style: solid;
+	border-width: 1px;
+	overflow: auto;
+	width: auto;
+	clear: none;
+	background: #eee;
+	color: black !important;
+}
+.recentchanges .metadata {
+	padding: 0px 0.5em;
+}
+.recentchanges .changelog {
+	font-style: italic;
+	clear: both;
+	display: block;
+	padding: 1px 2px;
+	background: white !important;
+	color: black !important;
+}
+.recentchanges .desc {
+	display: none;
+}
+.recentchanges .diff {
+	display: none;
+}
+.recentchanges .committer {
+	float: left;
+	margin: 0;
+	width: 40%;
+}
+.recentchanges .committype {
+	float: left;
+	margin: 0;
+	width: 5%;
+	font-size: small;
+}
+.recentchanges .changedate {
+	float: left;
+	margin: 0;
+	width: 35%;
+	font-size: small;
+}
+.recentchanges .pagelinks,
+.recentchanges .revert {
+	float: right;
+	margin: 0;
+	width: 60%;
+}
+
+.blogform, #blogform {
+	padding: 10px 10px;
+	border: 1px solid #aaa;
+	background: #eee;
+	color: black !important;

(Diff truncated)
add resource files for my ikiwiki trail plugin
diff --git a/local.css b/local.css
new file mode 100644
index 0000000..e57e876
--- /dev/null
+++ b/local.css
@@ -0,0 +1,2 @@
+@import url("/style/pcu.css");
+@import url("/style/trail.css");
diff --git a/style/trail.css b/style/trail.css
new file mode 100644
index 0000000..6b26540
--- /dev/null
+++ b/style/trail.css
@@ -0,0 +1,36 @@
+/* from IkiWiki branch */
+
+.trail {
+	display: block;
+	clear: both;
+	position: relative;
+}
+
+.trailprev {
+	display: block;
+	text-align: left;
+	position: absolute;
+	top: 0%;
+	left: 3%;
+	width: 30%;
+}
+
+.trailup {
+	display: block;
+	text-align: center;
+	margin-left: 35%;
+	margin-right: 35%;
+}
+
+.trailnext {
+	display: block;
+	text-align: right;
+	position: absolute;
+	top: 0%;
+	width: 30%;
+	right: 3%;
+}
+
+.trailsep {
+	display: none;
+}
diff --git a/templates/page.tmpl b/templates/page.tmpl
new file mode 100644
index 0000000..770ac23
--- /dev/null
+++ b/templates/page.tmpl
@@ -0,0 +1,207 @@
+<TMPL_IF HTML5><!DOCTYPE html>
+<html>
+<TMPL_ELSE><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+</TMPL_IF>
+<head>
+<TMPL_IF DYNAMIC>
+<TMPL_IF FORCEBASEURL><base href="<TMPL_VAR FORCEBASEURL>" /><TMPL_ELSE>
+<TMPL_IF BASEURL><base href="<TMPL_VAR BASEURL>" /></TMPL_IF>
+</TMPL_IF>
+</TMPL_IF>
+<TMPL_IF HTML5><meta charset="utf-8" /><TMPL_ELSE><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></TMPL_IF>
+<title><TMPL_VAR TITLE></title>
+<TMPL_IF FAVICON>
+<link rel="icon" href="<TMPL_VAR BASEURL><TMPL_VAR FAVICON>" type="image/x-icon" />
+</TMPL_IF>
+<link rel="stylesheet" href="<TMPL_VAR BASEURL>style.css" type="text/css" />
+<TMPL_IF LOCAL_CSS>
+<link rel="stylesheet" href="<TMPL_VAR BASEURL><TMPL_VAR LOCAL_CSS>" type="text/css" />
+<TMPL_ELSE>
+<link rel="stylesheet" href="<TMPL_VAR BASEURL>local.css" type="text/css" />
+</TMPL_IF>
+<TMPL_IF EDITURL>
+<link rel="alternate" type="application/x-wiki" title="Edit this page" href="<TMPL_VAR EDITURL>" />
+</TMPL_IF>
+<TMPL_IF FEEDLINKS><TMPL_VAR FEEDLINKS></TMPL_IF>
+<TMPL_IF RELVCS><TMPL_VAR RELVCS></TMPL_IF>
+<TMPL_IF META><TMPL_VAR META></TMPL_IF>
+<TMPL_LOOP TRAILLOOP>
+<TMPL_IF PREVPAGE>
+<link rel="prev" href="<TMPL_VAR PREVURL>" title="<TMPL_VAR PREVTITLE>" />
+</TMPL_IF>
+<link rel="up" href="<TMPL_VAR TRAILURL>" title="<TMPL_VAR TRAILTITLE>" />
+<TMPL_IF NEXTPAGE>
+<link rel="next" href="<TMPL_VAR NEXTURL>" title="<TMPL_VAR NEXTTITLE>" />
+</TMPL_IF>
+</TMPL_LOOP>
+</head>
+<body>
+
+<TMPL_IF HTML5><article class="page"><TMPL_ELSE><div class="page"></TMPL_IF>
+
+<TMPL_IF HTML5><section class="pageheader"><TMPL_ELSE><div class="pageheader"></TMPL_IF>
+<TMPL_IF HTML5><header class="header"><TMPL_ELSE><div class="header"></TMPL_IF>
+<span>
+<span class="parentlinks">
+<TMPL_LOOP PARENTLINKS>
+<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>/ 
+</TMPL_LOOP>
+</span>
+<span class="title">
+<TMPL_VAR TITLE>
+<TMPL_IF ISTRANSLATION>
+&nbsp;(<TMPL_VAR PERCENTTRANSLATED>%)
+</TMPL_IF>
+</span>
+</span>
+<TMPL_IF SEARCHFORM>
+<TMPL_VAR SEARCHFORM>
+</TMPL_IF>
+<TMPL_IF HTML5></header><TMPL_ELSE></div></TMPL_IF>
+
+<TMPL_IF HAVE_ACTIONS>
+<TMPL_IF HTML5><nav class="actions"><TMPL_ELSE><div class="actions"></TMPL_IF>
+<ul>
+<TMPL_IF EDITURL>
+<li><a href="<TMPL_VAR EDITURL>" rel="nofollow">Edit</a></li>
+</TMPL_IF>
+<TMPL_IF RECENTCHANGESURL>
+<li><a href="<TMPL_VAR RECENTCHANGESURL>">RecentChanges</a></li>
+</TMPL_IF>
+<TMPL_IF HISTORYURL>
+<li><a href="<TMPL_VAR HISTORYURL>">History</a></li>
+</TMPL_IF>
+<TMPL_IF GETSOURCEURL>
+<li><a href="<TMPL_VAR GETSOURCEURL>">Source</a></li>
+</TMPL_IF>
+<TMPL_IF PREFSURL>
+<li><a href="<TMPL_VAR PREFSURL>">Preferences</a></li>
+</TMPL_IF>
+<TMPL_IF ACTIONS>
+<TMPL_LOOP ACTIONS>
+<li><TMPL_VAR ACTION></li>
+</TMPL_LOOP>
+</TMPL_IF>
+<TMPL_IF COMMENTSLINK>
+<li><TMPL_VAR COMMENTSLINK></li>
+<TMPL_ELSE>
+<TMPL_IF DISCUSSIONLINK>
+<li><TMPL_VAR DISCUSSIONLINK></li>
+</TMPL_IF>
+</TMPL_IF>
+</ul>
+<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+
+<TMPL_IF OTHERLANGUAGES>
+<TMPL_IF HTML5><nav id="otherlanguages"><TMPL_ELSE><div id="otherlanguages"></TMPL_IF>
+<ul>
+<TMPL_LOOP OTHERLANGUAGES>
+<li>
+<a href="<TMPL_VAR URL>"><TMPL_VAR LANGUAGE></a>
+<TMPL_IF MASTER>
+(master)
+<TMPL_ELSE>
+&nbsp;(<TMPL_VAR PERCENT>%)
+</TMPL_IF>
+</li>
+</TMPL_LOOP>
+</ul>
+<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+
+<TMPL_VAR TRAILS>
+
+<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
+
+<TMPL_IF SIDEBAR>
+<TMPL_IF HTML5><aside class="sidebar"><TMPL_ELSE><div class="sidebar"></TMPL_IF>
+<TMPL_VAR SIDEBAR>
+<TMPL_IF HTML5></aside><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+
+<div id="pagebody">
+
+<TMPL_IF HTML5><section id="content"><TMPL_ELSE><div id="content"></TMPL_IF>
+<TMPL_VAR CONTENT>
+<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
+
+<TMPL_UNLESS DYNAMIC>
+<TMPL_IF COMMENTS>
+<TMPL_IF HTML5><section id="comments"><TMPL_ELSE><div id="comments"></TMPL_IF>
+<TMPL_VAR COMMENTS>
+<TMPL_IF ADDCOMMENTURL>
+<div class="addcomment">
+<a href="<TMPL_VAR ADDCOMMENTURL>">Add a comment</a>
+</div>
+<TMPL_ELSE>
+<div class="addcomment">Comments on this page are closed.</div>
+</TMPL_IF>
+<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+</TMPL_UNLESS>

(Diff truncated)
revert another test comment
This reverts commit 6002083290007c6a0040eef497f4fd2e48c08da5
diff --git a/2008/04/16/tp-svc/comment_1_5a54fb79415e9f1b6f920af57077d919._comment b/2008/04/16/tp-svc/comment_1_5a54fb79415e9f1b6f920af57077d919._comment
deleted file mode 100644
index 2684400..0000000
--- a/2008/04/16/tp-svc/comment_1_5a54fb79415e9f1b6f920af57077d919._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="http://smcv.pseudorandom.co.uk/"
- nickname="smcv"
- subject="a comment"
- date="2010-12-20T21:34:16Z"
- content="""
-no comment really
-"""]]

exclude /~, /_, ikiwiki.cgi for robots
diff --git a/robots.txt b/robots.txt
new file mode 100644
index 0000000..4903d0f
--- /dev/null
+++ b/robots.txt
@@ -0,0 +1,6 @@
+User-agent: *
+# Temporary directories start with _ or ~
+Disallow: /_
+Disallow: /~
+# IkiWiki for dynamic stuff
+Disallow: /ikiwiki.cgi

Comment moderation
diff --git a/2008/04/16/tp-svc/comment_1_5a54fb79415e9f1b6f920af57077d919._comment b/2008/04/16/tp-svc/comment_1_5a54fb79415e9f1b6f920af57077d919._comment
new file mode 100644
index 0000000..2684400
--- /dev/null
+++ b/2008/04/16/tp-svc/comment_1_5a54fb79415e9f1b6f920af57077d919._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="http://smcv.pseudorandom.co.uk/"
+ nickname="smcv"
+ subject="a comment"
+ date="2010-12-20T21:34:16Z"
+ content="""
+no comment really
+"""]]

ok, that worked
This reverts commit e04c984d55744f17cb064d4dce437eb7300c3dfe
diff --git a/2008/04/16/tp-svc/comment_1_1a3cc5ddd16b6695aabf761492b554af._comment b/2008/04/16/tp-svc/comment_1_1a3cc5ddd16b6695aabf761492b554af._comment
deleted file mode 100644
index 4c1604a..0000000
--- a/2008/04/16/tp-svc/comment_1_1a3cc5ddd16b6695aabf761492b554af._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="http://smcv.pseudorandom.co.uk/"
- nickname="smcv"
- subject="silly comment to make sure they still work"
- date="2010-12-05T20:30:07Z"
- content="""
-hello!
-"""]]

Comment moderation
diff --git a/2008/04/16/tp-svc/comment_1_1a3cc5ddd16b6695aabf761492b554af._comment b/2008/04/16/tp-svc/comment_1_1a3cc5ddd16b6695aabf761492b554af._comment
new file mode 100644
index 0000000..4c1604a
--- /dev/null
+++ b/2008/04/16/tp-svc/comment_1_1a3cc5ddd16b6695aabf761492b554af._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="http://smcv.pseudorandom.co.uk/"
+ nickname="smcv"
+ subject="silly comment to make sure they still work"
+ date="2010-12-05T20:30:07Z"
+ content="""
+hello!
+"""]]

retroactively add updated dates to avoid planet-flooding
diff --git a/2009/11/rcbw.mdwn b/2009/11/rcbw.mdwn
index 214af30..e1740e1 100644
--- a/2009/11/rcbw.mdwn
+++ b/2009/11/rcbw.mdwn
@@ -1,5 +1,6 @@
 [[!meta title="RC Bugs of W47"]]
 [[!meta date="2009-11-23T10:59:12+0000"]]
+[[!meta updated="2009-11-23T12:35:47Z"]]
 [[!meta copyright="Copyright © 2009 Simon McVittie"]]
 [[!tag debian rcbw]]
 
diff --git a/2009/11/tp-qt4.mdwn b/2009/11/tp-qt4.mdwn
index 64e96e9..fff0cf6 100644
--- a/2009/11/tp-qt4.mdwn
+++ b/2009/11/tp-qt4.mdwn
@@ -1,4 +1,6 @@
 [[!meta title="telepathy-qt4 0.2.0: first shared library release"]]
+[[!meta date="2009-11-10T18:09:27Z"]]
+[[!meta updated="2009-11-10T18:10:53Z"]]
 [[!meta copyright="Copyright © 2009 Simon McVittie"]]
 [[!tag telepathy]]
 
diff --git a/2009/12/gfcombinefs.mdwn b/2009/12/gfcombinefs.mdwn
index 371ef4a..1fd3c74 100644
--- a/2009/12/gfcombinefs.mdwn
+++ b/2009/12/gfcombinefs.mdwn
@@ -1,5 +1,6 @@
 [[!meta title="Announcing gfcombinefs"]]
 [[!meta date="2009-12-18T00:29:40+0000"]]
+[[!meta updated="2009-12-18T00:48:04Z"]]
 [[!meta copyright="Copyright © 2009 Simon McVittie"]]
 
 [gfcombinefs] is a side project I did some work on a few weeks ago. It
diff --git a/2009/12/rcbw48.mdwn b/2009/12/rcbw48.mdwn
index d08995d..5f16745 100644
--- a/2009/12/rcbw48.mdwn
+++ b/2009/12/rcbw48.mdwn
@@ -1,5 +1,6 @@
 [[!meta title="RC Bugs of W48-W49"]]
 [[!meta date="2009-12-07T10:57:20+0000"]]
+[[!meta updated="2009-12-07T14:45:48Z"]]
 [[!meta copyright="Copyright © 2009 Simon McVittie"]]
 [[!tag debian rcbw]]
 
diff --git a/2010/debian.mdwn b/2010/debian.mdwn
index 257d4b4..bd6a923 100644
--- a/2010/debian.mdwn
+++ b/2010/debian.mdwn
@@ -1,5 +1,6 @@
 [[!meta title="Debian activities"]]
 [[!meta date="2010-11-08T20:05:47+0000"]]
+[[!meta updated="2010-11-08T23:35:23Z"]]
 [[!meta copyright="Copyright © 2010 Simon McVittie"]]
 [[!tag debian rcbw]]
 

finally get round to blogging about ioquake3 and bugsquashing
diff --git a/2010.mdwn b/2010.mdwn
new file mode 100644
index 0000000..c8bbb59
--- /dev/null
+++ b/2010.mdwn
@@ -0,0 +1 @@
+[[!map pages="2010/* and copyright(*)" show=title]]
diff --git a/2010/debian.mdwn b/2010/debian.mdwn
new file mode 100644
index 0000000..257d4b4
--- /dev/null
+++ b/2010/debian.mdwn
@@ -0,0 +1,57 @@
+[[!meta title="Debian activities"]]
+[[!meta date="2010-11-08T20:05:47+0000"]]
+[[!meta copyright="Copyright © 2010 Simon McVittie"]]
+[[!tag debian rcbw]]
+
+Most of my recent Debian work has been the usual pkg-telepathy stuff (mainly
+in experimental while we're frozen), and hacking on the Quake III engine.
+
+Having started working on OpenArena DFSG-freeness as random bug-squashing a
+year ago, I've accidentally ended up taking over the package. The situation
+for Debian 6.0 (squeeze) looks something like this:
+
+* [[!debpts openarena]] contains both the engine (a modified
+  [ioquake3](http://ioquake3.org/), which I modified further for Debian) and
+  the game logic compiled to native code
+* [[!debpts openarena-data]] has had the bytecode game logic stripped out,
+  since no Free compiler can produce it; the bytecode has been replaced with
+  stub files that direct our modified engine to load native code
+
+The plan for Quake III in Debian 7.0 (wheezy) has already started in
+experimental:
+
+* [[!debpts ioquake3]] contains the [ioquake3.org](http://ioquake3.org/) port
+  of the Quake III engine, which I've modified to be able to run either
+  Quake III Arena or OpenArena based on runtime options
+* openarena contains the game logic compiled to native code (in experimental
+  it still contains source code for the engine, but it's no longer patched
+  or compiled, and I'll hopefully drop it entirely after the next upstream
+  release), and launcher scripts to run it under the ioquake3 engine
+* openarena-data is much like it is now, although it might move to
+  data.debian.org if that happens
+* [[!debpts quake3]] (currently in the NEW queue) contains launcher scripts
+  to run Quake III Arena under the ioquake3 engine, requiring a
+  non-distributable quake3-data package
+* [[!debpts game-data-packager]] version 23 or later can build the quake3-data
+  package for local use, if you give it pak0.pk3 (from the CD-ROM) and the
+  latest Quake III patch
+
+I haven't been doing as much QA work as the [[tags/RCBW]] crowd, but here's
+some halfway-recent bug squashing in the hope that it motivates others:
+
+* [[!debpts alsa-lib]] [[!debbug 589896]] upstream patch backported, NMU'd
+  and herded into testing
+* [[!debpts atftpd]] [[!debbug 598474]] downgraded
+* [[!debpts courier-authlib]] [[!debbug 554788]] patch submitted, uploaded
+* [[!debpts isc-dhcp]] [[!debbug 592361]] patch submitted, uploaded by
+  maintainer
+  by maintainer
+* [[!debpts mixxx]] [[!debbug 587110]] patch submitted, acked by maintainer
+* [[!debpts tar]] [[!debbug 602184]], [[!debbug 602209]] upstream patches
+  NMU'd
+* [[!debpts witty]] [[!debbug 591209]] patch submitted, although it doesn't
+  list copyright holders so probably isn't suitable for upload
+
+I also started looking at the series of bugs regarding Flash not compiled from
+source, but I mostly got distracted by all the webapps having a contrib/
+directory containing a million embedded code copies...

it's 2010
diff --git a/index.mdwn b/index.mdwn
index 195cf99..24fc35c 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -1,6 +1,6 @@
 [[!meta title="Background noise"]]
 [[!meta author="Simon McVittie"]]
-[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+[[!meta copyright="Copyright © 2008-2010 Simon McVittie"]]
 [[!meta permalink="http://smcv.pseudorandom.co.uk/"]]
 [[!meta openid="https://login.launchpad.net/+id/h7ezLtW"
   server="https://login.launchpad.net/+openid"]]
@@ -10,14 +10,14 @@
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
-[[!inline pages="(2009/* or 2008/*) and copyright(*) and !*/Discussion"
+[[!inline pages="20*/* and copyright(*) and !*/Discussion"
   show="5" actions="yes"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]
 
 Older posts:
 
-[[!inline pages="(2009/* or 2008/*) and copyright(*) and !*/Discussion"
+[[!inline pages="20*/* and copyright(*) and !*/Discussion"
   skip="5" atom="no" archive="yes"]]
 
 ----

Added a comment: bss03/master merged
diff --git a/2009/12/gfcombinefs/comment_5._comment b/2009/12/gfcombinefs/comment_5._comment
new file mode 100644
index 0000000..ad89cbe
--- /dev/null
+++ b/2009/12/gfcombinefs/comment_5._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="http://smcv.pseudorandom.co.uk/"
+ subject="bss03/master merged"
+ date="2010-01-18T14:30:47Z"
+ content="""
+bss03, thanks for your patch: I don't get those warnings anyway, but the changes look fine.
+"""]]

Added a comment
diff --git a/2009/12/gfcombinefs/comment_4._comment b/2009/12/gfcombinefs/comment_4._comment
new file mode 100644
index 0000000..5db2e67
--- /dev/null
+++ b/2009/12/gfcombinefs/comment_4._comment
@@ -0,0 +1,6 @@
+[[!comment format=mdwn
+ username="http://costela.net/"
+ date="2009-12-18T22:55:24Z"
+ content="""
+Oh man... I started writing exactly the same piece of software some months ago and never got around to finishing it. Hopefully I'll learn the lesson and release early code as fast as possible the next time.
+"""]]

Added a comment
diff --git a/2009/12/gfcombinefs/comment_3._comment b/2009/12/gfcombinefs/comment_3._comment
new file mode 100644
index 0000000..080a6a3
--- /dev/null
+++ b/2009/12/gfcombinefs/comment_3._comment
@@ -0,0 +1,6 @@
+[[!comment format=mdwn
+ username="https://launchpad.net/~bss03"
+ date="2009-12-18T06:03:35Z"
+ content="""
+Noticed you are still getting a gcc warning.  I've prepared a couple of patches to address the warning, although it is pretty clear the warning is a non-issue when the hooks provided are used sanely.  However, I found no documentation indicating that fuse_operations::read would always recieve a non-negative forth argument, so I figured at least a sanity check inside the function makes sense.  My patches are in the master branch of git://git.iguanasuicide.net/srv/git/gfcombinefs.
+"""]]

Added a comment: D'oh
diff --git a/2009/12/gfcombinefs/comment_2._comment b/2009/12/gfcombinefs/comment_2._comment
new file mode 100644
index 0000000..dac44b4
--- /dev/null
+++ b/2009/12/gfcombinefs/comment_2._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="http://www.steve.org.uk/"
+ subject="D'oh"
+ date="2009-12-18T02:41:57Z"
+ content="""
+Clearly I meant ``mutex`` - and I see now that you do destroy it at the end of main.  Late night.
+"""]]

Added a comment: Missing mutex initialisation?
diff --git a/2009/12/gfcombinefs/comment_1._comment b/2009/12/gfcombinefs/comment_1._comment
new file mode 100644
index 0000000..65472eb
--- /dev/null
+++ b/2009/12/gfcombinefs/comment_1._comment
@@ -0,0 +1,25 @@
+[[!comment format=htm
+ username="http://www.steve.org.uk/"
+ subject="Missing mutex initialisation?"
+ date="2009-12-18T02:39:52Z"
+ content="""
+<p>Don't you need to initialise the mutex first?</p>
+<p>e.g:</p>
+<code>
+<pre>
+void * gfc_init () { pthread_mutex_init (&_g_lock, NULL); return 0; }
+</pre></code>
+<p>Similarly destroy:</p>
+<code><pre>
+void gfc_destroy () { pthread_mutex_destroy (&_g_lock); }
+</pre>
+</code>
+<p>Then update your gfs_ops structure to include to have:</p>
+<code>
+<pre>
+    .init = gfc_init,
+    .destroy = gfc_destroy,
+</pre>
+</code>
+<p>I hope that didn't get mangled too much!</p>
+"""]]

Blog about gfcombinefs
diff --git a/2009/12/gfcombinefs.mdwn b/2009/12/gfcombinefs.mdwn
new file mode 100644
index 0000000..371ef4a
--- /dev/null
+++ b/2009/12/gfcombinefs.mdwn
@@ -0,0 +1,27 @@
+[[!meta title="Announcing gfcombinefs"]]
+[[!meta date="2009-12-18T00:29:40+0000"]]
+[[!meta copyright="Copyright © 2009 Simon McVittie"]]
+
+[gfcombinefs] is a side project I did some work on a few weeks ago. It
+combines several "shares" of a secret file previously split using Shamir
+secret sharing, to produce the original secret, and presents it as a file in
+a FUSE filesystem. It uses [libgfshare] for the actual mathematics, and
+expects its input to have been split with the `gfsplit` tool shipped with
+libgfshare.
+
+[gfcombinefs]: http://www.pseudorandom.co.uk/src/gfcombinefs/
+[libgfshare]: http://www.digital-scurf.org/software/libgfshare
+
+At this stage of development, I suggest not trusting it with important data,
+like the GnuPG secret keyrings it's designed for. However, I hope that with
+some feedback from others I can get it into a state where it's ready to
+be released and packaged (perhaps I'm being unnecessarily conservative, but
+for something that deals with GnuPG keys, it seems wise to be careful).
+
+Source code is available in [a git repository], and I'd welcome contributions,
+bug reports (other than the limitations that are already listed in the
+documentation) and in particular, a systematic code audit from someone (the
+good news is that there isn't very much code, so that shouldn't actually
+take long).
+
+[a git repository]: http://git.pseudorandom.co.uk/gfcombinefs.git

Blog about more RC bug squashing / package removals
diff --git a/2009/12.mdwn b/2009/12.mdwn
new file mode 100644
index 0000000..a37597a
--- /dev/null
+++ b/2009/12.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="December 2009"]]
+[[!map pages="2009/12/* and copyright(*)" show=title]]
diff --git a/2009/12/rcbw48.mdwn b/2009/12/rcbw48.mdwn
new file mode 100644
index 0000000..d08995d
--- /dev/null
+++ b/2009/12/rcbw48.mdwn
@@ -0,0 +1,46 @@
+[[!meta title="RC Bugs of W48-W49"]]
+[[!meta date="2009-12-07T10:57:20+0000"]]
+[[!meta copyright="Copyright © 2009 Simon McVittie"]]
+[[!tag debian rcbw]]
+
+More release critical bug squashing of the "week" (fortnight, really):
+
+* [[!debpts openarena-data]] [[!debbug 523323]] + patch (the necessary changes
+  in openarena are extensive, so I don't plan to NMU this unless there's no
+  response for a long time)
+* [[!debpts fuse]] [[!debbug 550334]], [[!debbug 553015]], [[!debbug 557143]]
+
+Removals from testing and proposed removals from unstable:
+
+* [[!debpts alien-arena]] [[!debbug 559725]] (removal from testing only)
+* [[!debpts commit-tool]] [[!debbug 558592]] (removal from testing only)
+* [[!debpts gadfly]] [[!debbug 559375]]
+* [[!debpts gaim-otr]] [[!debbug 552761]] (transitional package)
+* [[!debpts levee]] [[!debbug 558604]]
+* [[!debpts libroxen-adbanner]] [[!debbug 559251]]
+* [[!debpts libroxen-diary]] [[!debbug 559250]]
+* [[!debpts libroxen-imho]] [[!debbug 559249]] (removed from archive)
+* [[!debpts libroxen-tokenfs]] [[!debbug 559248]]
+* [[!debpts mailreader]] [[!debbug 559252]]
+* [[!debpts openc++]] [[!debbug 559111]]
+* [[!debpts overkill]] [[!debbug 558669]]
+* [[!debpts p3nfs]] [[!debbug 559105]]
+* [[!debpts portslave]] [[!debbug 559254]]
+* [[!debpts skyutils2]] [[!debbug 558605]] (removed from archive)
+* [[!debpts whirlpool]] [[!debbug 559255]]
+* [[!debpts ziproxy]] [[!debbug 559627]]
+
+Possible candidates for removal:
+
+* [[!debpts bfm]] (unmaintained upstream since 2004, declining popcon score)
+
+Other drive-by QA:
+
+* [[!debpts tse3]] [[!debbug 524726]] marked as done (by a binNMU)
+* [[!debpts joy2key]] [[!debbug 554521]] downgraded to important
+* [[!debpts nvidia-graphics-drivers]] [[!debbug 525414]] noted as probably
+  fixed, submitter/maintainer pinged for confirmation
+* Bugs filed about the packages keeping [[!debpts zope3]] around in testing:
+  [[!debbug 558204]], [[!debbug 558205]]
+* [[!debpts mail-notification-evolution]] [[!debbug 559106]] upgraded to
+  serious

RC-bugs of last week
diff --git a/2009/11/rcbw.mdwn b/2009/11/rcbw.mdwn
new file mode 100644
index 0000000..214af30
--- /dev/null
+++ b/2009/11/rcbw.mdwn
@@ -0,0 +1,45 @@
+[[!meta title="RC Bugs of W47"]]
+[[!meta date="2009-11-23T10:59:12+0000"]]
+[[!meta copyright="Copyright © 2009 Simon McVittie"]]
+[[!tag debian rcbw]]
+
+I've been intermittently prodding at the Debian release-critical bug list
+for some time, but inspired by
+[Zack](http://upsilon.cc/~zack/blog/posts/2009/11/RC_bugs_of_the_week_-_week_10/ )
+and [Tim](http://retout.co.uk/blog/2009/11/16/more-rc-bugs) I've decided to
+start keeping track, if only for my own interest.
+
+* Monday: [[!debpts openipmi]] [[!debbug 474087]] + patch (not uploaded since
+  I have no way to test IPMI libraries, not having the appropriate hardware...)
+
+* Monday: potential candidates for removal:
+  - [[!debpts skyutils]] (RC bug, library with no reverse dependencies since
+    smssend was removed in 2008)
+  - [[!debpts libhid]] (RC bug, RFA since August 2008, mainly exists to
+    support libphidgets)
+  - [[!debpts libphidgets]] (RC bug, RFA since 2007)
+  - [[!debpts libnoise]] (RC bug, library with no reverse dependencies or
+    popcon votes)
+
+* Thursday: [[!debpts hercules]] [[!debbug 553110]] uploaded to DELAYED/7,
+  with various bonus changes including making the copyright file sufficient
+  to satisfy Policy §12.5
+
+* Friday: [[!debpts spider]] [[!debbug 537631]] fixed by a QA upload,
+  fast-forwarding through 8 years of Debian policy and upgrading from debhelper
+  3 (!) to 7 in the process
+
+In general I've been trying to avoid resurrecting packages that I don't think
+should be in the archive, even if the fix is trivial. I'm not sure whether
+that applies to spider; according to
+<abbr title="popularity-contest">popcon</abbr>, it still has a substantial
+number of users, so it may be worth keeping even if there are no upstream
+releases (also, it amused me to convert such an old package to Debhelper 7
+and dpkg source format v3).
+
+In the process I've discovered that [[!debpkg git-buildpackage]] makes a great
+NMU tool. I'll probably be putting all future NMU diffs in my users/smcv
+directory on git.debian.org (at least until the maintainer acknowledges or
+rejects the NMU), just because it's a convenient way to give the maintainer
+a nice queue of individual changes rather than a monolithic diff; if any
+maintainers decide they'll use git as a result, that's a bonus :-)
diff --git a/tags/debian.mdwn b/tags/debian.mdwn
index 84fecaf..9227f6f 100644
--- a/tags/debian.mdwn
+++ b/tags/debian.mdwn
@@ -1,3 +1,5 @@
 [[!meta title="Debian"]]
 
+[Debian](http://www.debian.org/)-related things.
+
 [[!inline pages="link(/tags/debian)" archive="yes"]]
diff --git a/tags/rcbw.mdwn b/tags/rcbw.mdwn
new file mode 100644
index 0000000..b29f2c1
--- /dev/null
+++ b/tags/rcbw.mdwn
@@ -0,0 +1,5 @@
+[[!meta title="Release-critical Bugs of the Week"]]
+
+[[Debian]] [release-critical bugs of the week](http://upsilon.cc/~zack/blog/posts/2009/11/RC_bugs_of_the_week_-_week_10/).
+
+[[!inline pages="link(/tags/rcbw)" archive="yes"]]

typo
diff --git a/2009/11/tp-qt4.mdwn b/2009/11/tp-qt4.mdwn
index ffe7b1b..64e96e9 100644
--- a/2009/11/tp-qt4.mdwn
+++ b/2009/11/tp-qt4.mdwn
@@ -5,7 +5,7 @@
 This afternoon Andre released
 [telepathy-qt4](http://telepathy.freedesktop.org/wiki/Telepathy-Qt4) 0.2.0,
 the first version that builds a shared library, and I've uploaded it to Debian 
-it'll get into unstable as soon as it clears the NEW queue).
+(it'll get into unstable as soon as it clears the NEW queue).
 
 This is a major milestone for telepathy-qt4: over the course of 16 months'
 development it's gone from a collection of auto-generated constants (Olli

er, yeah, put a copyright on it so it gets into the blog feed
diff --git a/2009/11/tp-qt4.mdwn b/2009/11/tp-qt4.mdwn
index f3570b5..ffe7b1b 100644
--- a/2009/11/tp-qt4.mdwn
+++ b/2009/11/tp-qt4.mdwn
@@ -1,4 +1,5 @@
 [[!meta title="telepathy-qt4 0.2.0: first shared library release"]]
+[[!meta copyright="Copyright © 2009 Simon McVittie"]]
 [[!tag telepathy]]
 
 This afternoon Andre released

blog about telepathy-qt4 0.2.0
diff --git a/2009/05.mdwn b/2009/05.mdwn
new file mode 100644
index 0000000..2361f5c
--- /dev/null
+++ b/2009/05.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="May 2009"]]
+[[!map pages="2009/05/* and copyright(*)" show=title]]
diff --git a/2009/11.mdwn b/2009/11.mdwn
new file mode 100644
index 0000000..16d271e
--- /dev/null
+++ b/2009/11.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="November 2009"]]
+[[!map pages="2009/11/* and copyright(*)" show=title]]
diff --git a/2009/11/tp-qt4.mdwn b/2009/11/tp-qt4.mdwn
new file mode 100644
index 0000000..f3570b5
--- /dev/null
+++ b/2009/11/tp-qt4.mdwn
@@ -0,0 +1,20 @@
+[[!meta title="telepathy-qt4 0.2.0: first shared library release"]]
+[[!tag telepathy]]
+
+This afternoon Andre released
+[telepathy-qt4](http://telepathy.freedesktop.org/wiki/Telepathy-Qt4) 0.2.0,
+the first version that builds a shared library, and I've uploaded it to Debian 
+it'll get into unstable as soon as it clears the NEW queue).
+
+This is a major milestone for telepathy-qt4: over the course of 16 months'
+development it's gone from a collection of auto-generated constants (Olli
+Salli's initial commit, back in July 2008) to a shared library with a frozen
+API and ABI. We encourage Qt/KDE application developers to treat telepathy-qt4
+as the preferred Qt 4 binding for Telepathy.
+
+Andre and the rest of
+[the Telepathy project](http://telepathy.freedesktop.org/wiki/) will continue
+to add high-level bindings for more Telepathy features over the course of the
+0.3.x series; we plan to keep the API and ABI backwards-compatible until
+shortly before the next milestone, 0.4.0, at which point we'll consider
+breaking ABI to drop deprecated functionality.

Fix link into gitweb to point to the main repo
diff --git a/2008/09/pc-uninstalled.mdwn b/2008/09/pc-uninstalled.mdwn
index 36ad687..e03230e 100644
--- a/2008/09/pc-uninstalled.mdwn
+++ b/2008/09/pc-uninstalled.mdwn
@@ -65,7 +65,7 @@ Projects that *don't* do this correctly include telepathy-mission-control
 is obsolete).
 
 Today I committed a patch to telepathy-glib, inspired by GStreamer, to
-[generate telepathy-glib-uninstalled.pc](http://git.collabora.co.uk/?p=user/smcv/telepathy-glib-smcv.git;a=commitdiff;h=ea53d448e9d014936be66b5e3d22080decab1347).
+[generate telepathy-glib-uninstalled.pc](http://git.collabora.co.uk/?p=telepathy-glib.git;a=commitdiff;h=9961fd9e317be4048d0e6b71cf59596a26b32cd5).
 The presence of this patch simplifies the process further, to:
 
     ./autogen.sh PKG_CONFIG_PATH=$HOME/Collabora/tpglib/telepathy-glib

removed
diff --git a/2009/05/tp-proxy/comment_1._comment b/2009/05/tp-proxy/comment_1._comment
deleted file mode 100644
index e39775e..0000000
--- a/2009/05/tp-proxy/comment_1._comment
+++ /dev/null
@@ -1,6 +0,0 @@
-[[!_comment format=mdwn
- username="http://smcv.pseudorandom.co.uk/"
- date="2009-05-02T19:53:07Z"
- content="""
-ensuring that comments are actually possible now
-"""]]

Added a comment
diff --git a/2009/05/tp-proxy/comment_1._comment b/2009/05/tp-proxy/comment_1._comment
new file mode 100644
index 0000000..e39775e
--- /dev/null
+++ b/2009/05/tp-proxy/comment_1._comment
@@ -0,0 +1,6 @@
+[[!_comment format=mdwn
+ username="http://smcv.pseudorandom.co.uk/"
+ date="2009-05-02T19:53:07Z"
+ content="""
+ensuring that comments are actually possible now
+"""]]

Blog about TpProxy, finally
diff --git a/2009/05/dbusgproxy-300.png b/2009/05/dbusgproxy-300.png
new file mode 100644
index 0000000..768b1e9
Binary files /dev/null and b/2009/05/dbusgproxy-300.png differ
diff --git a/2009/05/tp-proxy.mdwn b/2009/05/tp-proxy.mdwn
new file mode 100644
index 0000000..2a66acb
--- /dev/null
+++ b/2009/05/tp-proxy.mdwn
@@ -0,0 +1,458 @@
+[[!meta title="Implementing D-Bus clients with telepathy-glib (and telepathy-qt4)"]]
+[[!meta copyright="Copyright © 2009 Collabora Ltd."]]
+[[!tag telepathy d-bus]]
+[[!meta description="Implementing D-Bus clients with TpProxy and auto-generated API stubs"]]
+
+*(The much-delayed part 2 in an ongoing series: shiny things in
+telepathy-glib)*
+
+[[Over a year ago|/2008/04/16/tp-svc]] I explained my first major
+round of work on telepathy-glib, with which it could be used to implement
+D-Bus services. I started to write this post shortly after, but then got
+distracted by a bee or something; recent discussion about
+[having a D-Bus binding in GLib](http://bugzilla.gnome.org/show_bug.cgi?id=579571)
+has finally prompted me to finish it.
+
+The second major round of work on telepathy-glib dealt with implementing client
+code, and went sufficiently well that telepathy-qt4 (currently under
+development) uses essentially the same model.
+
+Again, while telepathy-glib is intended for Telepathy implementors,
+I think TpProxy's ideas are generically useful, particularly for "large"
+D-Bus APIs.
+
+## Some background: dbus-glib and libtelepathy
+
+[[!template id=note text="""
+[[!img /2009/05/dbusgproxy-300.png size="full" link="no"
+  alt="GObject-CRITICAL: Assertion failed: proxy->convenient"
+  title="GObject-CRITICAL: Assertion failed: proxy->convenient"]]<br />
+
+The life-cycle of a DBusGProxy (PD clipart credit:
+[karderio](http://openclipart.org/media/files/karderio/833) and
+[Andy](http://openclipart.org/media/files/Andy/68))
+"""]]
+
+The API provided by dbus-glib for client code is, er, rather less than ideal.
+The basic object is `DBusGProxy`, which has a few problems.
+
+There's one per interface, rather than one per object; this leads to a maze
+of twisty GObjects, all suspiciously similar. Our old client library,
+`libtelepathy`, got round this by subclassing ``DBusGProxy`` to make helper
+objects called `TpChan`, `TpConn` etc., which were simultaneously the
+proxy for the "main" interface (Channel, Connection etc.), and a factory for
+proxies for the other interfaces (like Channel.Type.Text and
+Channel.Interface.Password). This still wasn't ideal, but it was a start.
+
+If you use a DBusGProxy in any way after it has emitted the
+`destroy` signal, this is considered to be invalid use of the API, and
+dbus-glib asserts all over the place. We'd rather it didn't do that - remote
+objects becoming invalid is a fact of life, and if you don't immediately
+discard all your references to those objects, remote operations on them should
+just give you a runtime error. You have to be prepared to handle such runtime
+errors already, because any IPC call can fail at any time.
+
+The main API for calling methods uses varargs and is rather subtle. Notably,
+the calling convention for variant parameters (of D-Bus signature '`v`') is not
+consistent with the calling convention for any other container. For any
+other container, for instance a `GPtrArray *`, you pass in a `GPtrArray **`
+pointing to a `GPtrArray *` variable containing ``NULL``; on success,
+a pointer to a new `GPtrArray` is written into that variable. For variant
+parameters, though, you must pass in a `GValue *` pointing to a
+zero-filled `GValue`, and the result will be written into that `GValue`.
+
+`dbus-binding-tool` generates thin wrappers around this method-calling API
+which provide type-safety, although they can't directly specify a non-default
+timeout.
+
+As for signals, before binding to a signal, you have to tell dbus-glib about
+its signature. This tells dbus-glib how it should push the signal arguments
+onto the C stack (in GObject terminology: how it should marshal them), to
+match the signature of the signal-handler function.
+
+The documentation claims that this isn't necessary for objects supporting the
+`Introspect` method, but that's untrue - on the other hand, if the documented
+behaviour actually happened, I would consider this to be a critical bug in
+dbus-glib, since it would enable remote objects to crash dbus-glib clients
+(by causing signal arguments to be pushed onto the stack in a way that does
+not match the signature of the signal handler).
+
+Of course, the signal-adding function takes varargs, and has to be called
+exactly once per signal per object. If you don't, dbus-glib asserts when you
+connect to the signal; if you call it twice, dbus-glib asserts anyway.
+
+## `TpProxy`
+
+`TpProxy` is a `GObject` subclass vaguely inspired by Python's
+dbus.proxy.ProxyObject. It *isn't* a subclass of `DBusGProxy`, which lets us
+encapsulate dbus-glib almost completely - in fact, all the references to
+`DBusGProxy` are in a separate header, `proxy-subclass.h`, only used by
+subclasses of `TpProxy` (as opposed to normal library API users).
+
+`TpProxy` instances are per-remote-object (per-object-path) like in
+dbus-python, rather than per-interface like in dbus-glib or QtDBus. As
+explained below, I believe that this is the most natural object mapping for
+D-Bus interfaces; in practice it tends to lead to clearer code for us,
+since one remote object often maps nicely to one UI element (of course, if
+your objects only have one interface, this approach is no better or worse
+than dbus-glib's).
+
+`TpProxy` provides support for the following common D-Bus things:
+
+* Calling methods
+* Connecting to signals
+* Objects becoming invalid
+* Objects with optional interfaces
+* Extensibility
+
+It doesn't currently provide any particular help with Properties - the
+Properties interface is just another interface as far as we're concerned. We
+find that, in practice, that's not a problem (even though we use D-Bus
+properties extensively).
+
+In telepathy-qt4 we basically reinvented `TpProxy` in C++, as `Tp::DBusProxy`.
+I've put in some comments below illustrating how the general ideas we used
+in `TpProxy` translate into a different object mapping.
+
+## Calling methods
+
+Method calls on `TpProxy` are done through auto-generated wrapper functions,
+much like `DBusGProxy`. These look something like this:
+
+    typedef void (*tp_cli_channel_callback_for_close) (TpChannel *proxy,
+        /* any 'out' arguments would go here - Close() doesn't have any */
+        const GError *error, gpointer user_data,
+        GObject *weak_object);
+
+    TpProxyPendingCall *tp_cli_channel_call_close (TpChannel *proxy,
+        gint timeout_ms,
+        /* any 'in' arguments would go here - Close() doesn't have any */
+        tp_cli_channel_callback_for_close callback,
+        gpointer user_data,
+        GDestroyNotify destroy,
+        GObject *weak_object);
+
+Methods for some interfaces, like `DBus.Properties`, are available on `TpProxy`
+itself; others, like Telepathy's `Channel.anything`, are only available on a
+particular subclass, like `TpChannel`.
+
+Things to note here:
+
+* It's an asynchronous call with a callback. General design principle:
+  "this is IPC, get over it". We don't try to hide the fact that IPC is
+  taking place by doing [[pseudo-blocking calls|/2008/11/nonblocking]].
+
+* The timeout is explicit (although you can always pass -1 to let libdbus
+  pick a "reasonable" default for you). This is because the remote service
+  might not respond, and API users should be at least vaguely aware of this:
+  "this is IPC, get over it".
+
+* The callback isn't a `GCallback`; it has an explicit signature, for some
+  semblance of type-safety (it's not much, but it's better than nothing).
+
+* The callback takes a `GError`, because any IPC call can fail for any reason.
+
+* A `TpProxyPendingCall *` is returned. This is a pointer to an object that
+  only exists until just after the callback is called (so you can ignore it if
+  you don't want it), with a method you can call to cancel the method call
+  (with hindsight this is not ideal, and if I was writing this API now, I'd
+  use gio's `GCancellable`). "Cancel" is perhaps slightly misleading: the
+  method call still takes place (it was already in libdbus's outgoing queue)
+  but the result gets ignored and the callback isn't called. This is mostly
+  so you an object can forget all the calls it was busy making at the time
+  that the results become irrelevant (e.g. the object is destroyed).
+
+* There is an extra `weak_object` argument, which is weakly referenced and is
+  passed to the callback: in practice, most users of telepathy-glib use this
+  as well as or instead of `user_data`. If the `weak_object` runs out of
+  references, the callback is automatically cancelled, which means that
+  in practice, explicit cancellation is almost never needed.
+
+* The generated code has as its first argument a suitable subclass of
+  `TpProxy`, in this case `TpChannel` (we tell the code generator about
+  subclasses).
+
+* You can't see it in the API, but the `TpProxy` gains an extra ref while a
+  method call is in progress, so you never have to worry about what happens
+  if the proxy gets unreffed during a method call.
+
+* There's an explicit destructor for the `user_data`, which is called even if
+  you "cancel" the method call.
+
+In telepathy-qt4, these methods are on small generated helper classes similar
+to dbus-python's `dbus.Interface`, one per interface (we provide accessors for
+them on the non-generated `DBusProxy` subclass). Instead of using callbacks,
+we return a temporary `QObject` per call, which emits a Qt signal on success
+or failure (that's how all async calls in QtDBus work).
+
+## Connecting to signals
+
+Similarly, signals have some generated functions:

(Diff truncated)
dspam frustrations
diff --git a/2009/04.mdwn b/2009/04.mdwn
new file mode 100644
index 0000000..d66d364
--- /dev/null
+++ b/2009/04.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="April 2009"]]
+[[!map pages="2009/04/* and copyright(*)" show=title]]
diff --git a/2009/04/dspam.mdwn b/2009/04/dspam.mdwn
new file mode 100644
index 0000000..0623d5e
--- /dev/null
+++ b/2009/04/dspam.mdwn
@@ -0,0 +1,35 @@
+[[!meta title="DSpam and how not to do it"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2009/04/dspam/"]]
+[[!meta date="2009-04-13T21:57:39+0100"]]
+[[!meta copyright="Copyright © 2009 Simon McVittie"]]
+[[!tag sysadmin]]
+
+At some point I might document my current e-mail setup, but for now, here's
+the bit that caused plenty of frustration on Friday. Many howtos for postfix
+and dspam will tell you that if you embed user IDs in the signature with
+`PgSQLUIDInSignature on` (or the MySQL equivalent, you can do something like
+this for retraining, and set it up to receive spam@example.com:
+
+    # master.cf
+    dspamretrain unix -     n       n       -       10      pipe
+      flags=R user=dspam argv=/usr/bin/dspam --user dspam
+          --class=${nexthop} --source=error
+
+    # mailbox_transport map
+    spam    dspamretrain:spam
+    notspam dspamretrain:innocent
+
+in which `--user dspam` names an arbitrary user (dspam will extract the uid
+from the signature and switch from "dspam" to the correct user, but the
+command line argument is still required, for no particular reason).
+
+I said it named an arbitrary user, but actually that's a lie. The things to
+be careful of are:
+
+* the dspam user must be listed in your database (e.g. in dspam_virtual_uids
+  for postgres users with the default setup)
+* if you're running dspam in opt-in mode, dspam must have opted in
+  (so create /var/spool/dspam/opt-in/local/dspam.dspam)
+
+Having failed at both of those, my retrain address wasn't working, and sadness
+ensued.

Add tags pages
diff --git a/tags.mdwn b/tags.mdwn
new file mode 100644
index 0000000..53731a0
--- /dev/null
+++ b/tags.mdwn
@@ -0,0 +1,5 @@
+[[!meta title="Tags"]]
+
+[[!pagestats pages="tags/*"]]
+
+[[!map pages="tags/*" show="title"]]
diff --git a/tags/d-bus.mdwn b/tags/d-bus.mdwn
new file mode 100644
index 0000000..7f2e5ae
--- /dev/null
+++ b/tags/d-bus.mdwn
@@ -0,0 +1,3 @@
+[[!meta title="D-Bus"]]
+
+[[!inline pages="link(/tags/d-bus)" archive="yes"]]
diff --git a/tags/debian.mdwn b/tags/debian.mdwn
new file mode 100644
index 0000000..84fecaf
--- /dev/null
+++ b/tags/debian.mdwn
@@ -0,0 +1,3 @@
+[[!meta title="Debian"]]
+
+[[!inline pages="link(/tags/debian)" archive="yes"]]
diff --git a/tags/git.mdwn b/tags/git.mdwn
new file mode 100644
index 0000000..c90b301
--- /dev/null
+++ b/tags/git.mdwn
@@ -0,0 +1,3 @@
+[[!meta title="Git"]]
+
+[[!inline pages="link(/tags/git)" archive="yes"]]
diff --git a/tags/sysadmin.mdwn b/tags/sysadmin.mdwn
new file mode 100644
index 0000000..9452ed0
--- /dev/null
+++ b/tags/sysadmin.mdwn
@@ -0,0 +1,3 @@
+[[!meta title="System administration"]]
+
+[[!inline pages="link(/tags/sysadmin)" archive="yes"]]
diff --git a/tags/telepathy.mdwn b/tags/telepathy.mdwn
new file mode 100644
index 0000000..510bafa
--- /dev/null
+++ b/tags/telepathy.mdwn
@@ -0,0 +1,3 @@
+[[!meta title="Telepathy"]]
+
+[[!inline pages="link(/tags/telepathy)" archive="yes"]]

Set dates and tags on posts
diff --git a/2008/04/01/codegen.mdwn b/2008/04/01/codegen.mdwn
index 5519f36..eb75c59 100644
--- a/2008/04/01/codegen.mdwn
+++ b/2008/04/01/codegen.mdwn
@@ -1,8 +1,9 @@
 [[!meta title="Here's how it works"]]
 [[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/01/codegen/"]]
 [[!meta date="2008-04-01T18:21:06Z"]]
-[[!meta atom.entry.updated="2008-04-01T18:21:06Z"]]
+[[!meta updated="2008-04-01T18:21:06Z"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
+[[!tag telepathy]]
 
 [Daf] recently described a large part of my job, in diagrammatic form:
 
diff --git a/2008/04/16/tp-svc.mdwn b/2008/04/16/tp-svc.mdwn
index 2c8bbf2..575ed15 100644
--- a/2008/04/16/tp-svc.mdwn
+++ b/2008/04/16/tp-svc.mdwn
@@ -2,9 +2,9 @@
 [[!meta description="Implementing services with auto-generated GInterfaces"]]
 [[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/16/tp-svc/"]]
 [[!meta date="2008-04-16T20:36:52Z"]]
-[[!meta atom.entry.updated="2008-04-16T22:07:52Z"]]
+[[!meta updated="2008-12-22T22:38:00Z"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
-[[!tag smcv.pseudorandom.co.uk]]
+[[!tag smcv.pseudorandom.co.uk telepathy d-bus]]
 
 *(Part 1 of an ongoing series: shiny things in telepathy-glib)*
 
diff --git a/2008/05/16/onaplane.mdwn b/2008/05/16/onaplane.mdwn
index c15e268..65253b0 100644
--- a/2008/05/16/onaplane.mdwn
+++ b/2008/05/16/onaplane.mdwn
@@ -1,8 +1,9 @@
 [[!meta title="Spec-writing On A Plane"]]
 [[!meta guid="http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/"]]
 [[!meta date="2008-05-19T10:03:00Z"]]
-[[!meta atom.entry.updated="2008-05-19T10:03:00Z"]]
+[[!meta updated="2008-05-19T10:03:00Z"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
+[[!tag telepathy]]
 
 (Written on Friday 16th, posted on Monday)
 
diff --git a/2008/09/cryptroot.mdwn b/2008/09/cryptroot.mdwn
index 247475b..4b404dd 100644
--- a/2008/09/cryptroot.mdwn
+++ b/2008/09/cryptroot.mdwn
@@ -1,6 +1,8 @@
 [[!meta title="Encrypted root filesystem on a Debian laptop"]]
 [[!meta date="2008-09-11T16:36:00+0100"]]
+[[!meta updated="2008-09-14T17:45:00+0100"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
+[[!tag debian sysadmin]]
 
 I've been meaning to document this for ages...
 
diff --git a/2008/09/eoc.mdwn b/2008/09/eoc.mdwn
index ec8b1d4..942987c 100644
--- a/2008/09/eoc.mdwn
+++ b/2008/09/eoc.mdwn
@@ -1,6 +1,8 @@
 [[!meta title="Integrating Enemies of Carlotta with Postfix"]]
 [[!meta date="2008-09-02T11:48:43+0300"]]
+[[!meta updated="2008-09-03T14:12:00+0100"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie / Rob McQueen"]]
+[[!tag sysadmin]]
 
 From the "doing sysadmin over wobbly 3G while waiting for our plane to be
 allowed to take off" department comes this bit of mailing list setup.
diff --git a/2008/09/pc-uninstalled.mdwn b/2008/09/pc-uninstalled.mdwn
index 446a3f9..36ad687 100644
--- a/2008/09/pc-uninstalled.mdwn
+++ b/2008/09/pc-uninstalled.mdwn
@@ -1,5 +1,6 @@
 [[!meta title="Compiling against uninstalled versions of libraries"]]
 [[!meta date="2008-09-03T18:30:54+0100"]]
+[[!meta updated="2009-01-13T16:34:00+0000"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
 
 Developers seem to do a lot of fighting with bleeding-edge libraries installed
diff --git a/2008/11/nonblocking.mdwn b/2008/11/nonblocking.mdwn
index 229a08f..4d26bde 100644
--- a/2008/11/nonblocking.mdwn
+++ b/2008/11/nonblocking.mdwn
@@ -1,7 +1,9 @@
 [[!meta title="Why you shouldn't block on D-Bus calls"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
 [[!meta date="2008-11-24T17:05:06+0000"]]
+[[!meta updated="2008-11-24T17:13:06+0000"]]
 [[!meta guid="urn:uuid:46dd715c-58bf-485a-9431-9be18cc58300"]]
+[[!tag d-bus]]
 
 I've found myself writing this several times recently in the context
 of Telepathy, so I thought I'd make a blog post that I can refer people to.
diff --git a/2009/01/08_debian_bzr_to_git.mdwn b/2009/01/08_debian_bzr_to_git.mdwn
index 3d8cfb0..98ba67c 100644
--- a/2009/01/08_debian_bzr_to_git.mdwn
+++ b/2009/01/08_debian_bzr_to_git.mdwn
@@ -1,7 +1,9 @@
 [[!meta title="Converting Debian packaging from bzr to git"]]
 [[!meta guid="http://smcv.pseudorandom.co.uk/2009/01/08_debian_bzr_to_git/"]]
 [[!meta date="2009-01-08T21:08:00+0000"]]
+[[!meta updated="2009-01-08T21:19:00+0000"]]
 [[!meta copyright="Copyright © 2009 Simon McVittie"]]
+[[!tag debian git]]
 
 I recently converted most of the Debian packaging for Telepathy and related
 projects from bzr to git, while changing the repository contents from just
diff --git a/index.mdwn b/index.mdwn
index cf22138..195cf99 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -5,6 +5,8 @@
 [[!meta openid="https://login.launchpad.net/+id/h7ezLtW"
   server="https://login.launchpad.net/+openid"]]
 
+[[!pagestats pages="tags/*"]]
+
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 

Fix example pkg-config invocation
diff --git a/2008/09/pc-uninstalled.mdwn b/2008/09/pc-uninstalled.mdwn
index 52a7784..446a3f9 100644
--- a/2008/09/pc-uninstalled.mdwn
+++ b/2008/09/pc-uninstalled.mdwn
@@ -26,9 +26,9 @@ same process.
 In my Gabble checkout, I used to configure like this:
 
     cd ~/Collabora/telepathy/gabble
+    ./autogen.sh \
     TP_GLIB_CFLAGS="-I${HOME}/Collabora/telepathy/tpglib" \
-    TP_GLIB_LIBS="${HOME}/Collabora/telepathy/tpglib/telepathy-glib/libtelepathy-glib.la" \
-    sh ./autogen.sh
+    TP_GLIB_LIBS="${HOME}/Collabora/telepathy/tpglib/telepathy-glib/libtelepathy-glib.la"
 
 This would make libtool link Gabble against the copy of telepathy-glib built by
 my bleeding-edge git checkout, without ever needing to install it.
@@ -67,7 +67,7 @@ Today I committed a patch to telepathy-glib, inspired by GStreamer, to
 [generate telepathy-glib-uninstalled.pc](http://git.collabora.co.uk/?p=user/smcv/telepathy-glib-smcv.git;a=commitdiff;h=ea53d448e9d014936be66b5e3d22080decab1347).
 The presence of this patch simplifies the process further, to:
 
-    PKG_CONFIG_PATH=$HOME/Collabora/tpglib/telepathy-glib sh ./autogen.sh
+    ./autogen.sh PKG_CONFIG_PATH=$HOME/Collabora/tpglib/telepathy-glib
 
 This has the same benefits as setting TP_GLIB_CFLAGS and TP_GLIB_LIBS,
 but is easier to remember, and is more future-proof against changes to
@@ -76,3 +76,10 @@ telepathy-glib.
 It only works because pkg-config has a special case for this situation -
 if you ask for the package "foo", pkg-config will always look for
 foo-uninstalled.pc before foo.pc.
+
+(Edited 2009-01-13: putting environment variables on the ./configure or
+./autogen.sh command line like `./autogen.sh PKG_CONFIG_PATH=foo` is better
+than putting them in the environment like `PKG_CONFIG_PATH=foo ./autogen.sh`,
+since it works around
+[Debian bug #398901](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=398901)
+and bugs like it)

Fix formatting
diff --git a/2009/01/08_debian_bzr_to_git.mdwn b/2009/01/08_debian_bzr_to_git.mdwn
index 67ad945..3d8cfb0 100644
--- a/2009/01/08_debian_bzr_to_git.mdwn
+++ b/2009/01/08_debian_bzr_to_git.mdwn
@@ -1,6 +1,6 @@
 [[!meta title="Converting Debian packaging from bzr to git"]]
 [[!meta guid="http://smcv.pseudorandom.co.uk/2009/01/08_debian_bzr_to_git/"]]
-[[!meta date="2009-01-08T00:50:11+0000"]]
+[[!meta date="2009-01-08T21:08:00+0000"]]
 [[!meta copyright="Copyright © 2009 Simon McVittie"]]
 
 I recently converted most of the Debian packaging for Telepathy and related
@@ -8,30 +8,28 @@ projects from bzr to git, while changing the repository contents from just
 the debian/ directory to the whole source tree. Here's the recipe, using the
 latest one to be converted (pymsn) as an example.
 
-## Create a repository
+### Create a repository
 
-* mkdir pymsn
+    mkdir pymsn
+    cd pymsn
+    git init
 
-* cd pymsn
-
-* git init
-
-## Mass tarball import
+### Mass tarball import
 
 * download all the tarballs into ../tarballs
 
 * rename all the tarballs to *.orig.tar.gz:
 
         rename 's/^pymsn-/pymsn_/' *.tar.gz
-	rename 's/\.tar\.gz$/.orig.tar.gz/' *.tar.gz
+        rename 's/\.tar\.gz$/.orig.tar.gz/' *.tar.gz
 
 * use `git-import-orig` to import them:
 
-	cd ../pymsn
+        cd ../pymsn
         ls ../tarballs/pymsn_*.orig.tar.gz
         for v in 0.2 0.2.1 0.2.2 0.3.0 0.3.1 0.3.2 0.3.3; do \
-	git-import-orig --no-merge --no-dch --pristine-tar \
-	    -u $v ../tarballs/pymsn_$v.orig.tar.gz; done
+        git-import-orig --no-merge --no-dch --pristine-tar \
+            -u $v ../tarballs/pymsn_$v.orig.tar.gz; done
 
 * throw away the resulting `master` branch in favour of using one we convert
   from bzr later:
@@ -39,7 +37,7 @@ latest one to be converted (pymsn) as an example.
         git checkout upstream
         git branch -D master
 
-## Converting the Debian packaging
+### Converting the Debian packaging
 
 This has the slight complication that in some (but not all) of the bzr commits,
 the repository contained only the contents of the debian directory, in the
@@ -72,7 +70,7 @@ root of the repository. So, I needed to rewrite history, with this script:
 
         git branch -m master debian
 
-	git branch -D tmp
+        git branch -D tmp
 
 * Rewrite history so changelog, control etc. are consistently inside a debian
   directory, with the script shown above:
@@ -86,65 +84,64 @@ root of the repository. So, I needed to rewrite history, with this script:
 * Merge the appropriate upstream versions into each branch:
 
         git checkout debian
-	git merge upstream/0.3.3
-	vim debian/control        # and change Vcs-Bzr to Vcs-Git
-	dch "Move packaging to git"
-	debcommit -a
+        git merge upstream/0.3.3
+        vim debian/control        # and change Vcs-Bzr to Vcs-Git
+        dch "Move packaging to git"
+        debcommit -a
 
         git checkout debian-lenny
-	git merge upstream/0.3.1
-	vim debian/control        # and change Vcs-Bzr to Vcs-Git
-	dch "Move packaging to git"
-	debcommit -a
+        git merge upstream/0.3.1
+        vim debian/control        # and change Vcs-Bzr to Vcs-Git
+        dch "Move packaging to git"
+        debcommit -a
 
 * Rescue Debian patches and put them on a debian-patches branch, which is
-  rebased with each upstream release:
+  rebased with each upstream release. For pymsn, there aren't any patches in
+  the debian branch at the moment:
 
-	# there aren't any patches in the debian branch at the moment
         git branch debian-patches upstream/0.3.3
 
-	# but there is one in the debian-lenny branch
+  but there is one in the debian-lenny branch:
+
         git branch debian-lenny-patches upstream/0.3.1
-	git checkout debian-lenny
-	cp debian/patches/00-fix-dns-resolution.diff ..
-	git checkout debian-lenny-patches
-	patch -p1 < ../00-fix-dns-resolution.diff
-	git commit -a
+        git checkout debian-lenny
+        cp debian/patches/00-fix-dns-resolution.diff ..
+        git checkout debian-lenny-patches
+        patch -p1 < ../00-fix-dns-resolution.diff
+        git commit -a
 
 * Make a repository on alioth:
 
-        # on alioth
         cd /git/pkg-telepathy
-	GIT_DIR=pymsn.git git init --bare --shared
-	GIT_DIR=pymsn.git git config hooks.mailinglist ...
-	vim pymsn.git/description
+        GIT_DIR=pymsn.git git init --bare --shared
+        GIT_DIR=pymsn.git git config hooks.mailinglist ...
+        vim pymsn.git/description
 
 * Push to the repository:
 
-	git gc --aggressive
-	git remote add origin git+ssh://git.debian.org/git/pkg-telepathy/pymsn.git
-	git push --all
+        git gc --aggressive
+        git remote add origin git+ssh://git.debian.org/git/pkg-telepathy/pymsn.git
+        git push --all
 
-* Do some more setup after the initial push:
+* On alioth, do some more setup after the initial push:
 
-	# on alioth
-	cat > pymsn.git/hooks/post-receive <<EOF
-	#!/bin/sh
-	exec /usr/local/bin/git-commit-notice
-	EOF
-	chmod +x pymsn.git/hooks/post-receive
-	GIT_DIR=pymsn.git git symbolic-ref HEAD refs/heads/debian
+        cat > pymsn.git/hooks/post-receive <<EOF
+        #!/bin/sh
+        exec /usr/local/bin/git-commit-notice
+        EOF
+        chmod +x pymsn.git/hooks/post-receive
+        GIT_DIR=pymsn.git git symbolic-ref HEAD refs/heads/debian
 
 * Mark the old repositories as no longer used:
 
         cd ../pymsn-unstable
-	dch $'This repository is no longer used, instead please use git:\n'\
-	"git://git.debian.org/git/pkg-telepathy/pymsn.git" -c changelog
-	debcommit -c changelog
-	bzr push
+        dch $'This repository is no longer used, instead please use git:\n'\
+        "git://git.debian.org/git/pkg-telepathy/pymsn.git" -c changelog
+        debcommit -c changelog
+        bzr push
         cd ../pymsn-experimental
-	dch $'This repository is no longer used, instead please use git:\n'\
-	"git://git.debian.org/git/pkg-telepathy/pymsn.git" -c changelog
-	debcommit -c changelog
-	bzr push
-	cd ../pymsn
+        dch $'This repository is no longer used, instead please use git:\n'\
+        "git://git.debian.org/git/pkg-telepathy/pymsn.git" -c changelog
+        debcommit -c changelog
+        bzr push
+        cd ../pymsn

Blog post: converting debian packaging from bzr to git
diff --git a/2009.mdwn b/2009.mdwn
new file mode 100644
index 0000000..ae589b5
--- /dev/null
+++ b/2009.mdwn
@@ -0,0 +1 @@
+[[!map pages="2009/* and copyright(*)" show=title]]
diff --git a/2009/01.mdwn b/2009/01.mdwn
new file mode 100644
index 0000000..f9e9958
--- /dev/null
+++ b/2009/01.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="January 2009"]]
+[[!map pages="2009/01/* and copyright(*)" show=title]]
diff --git a/2009/01/08_debian_bzr_to_git.mdwn b/2009/01/08_debian_bzr_to_git.mdwn
new file mode 100644
index 0000000..67ad945
--- /dev/null
+++ b/2009/01/08_debian_bzr_to_git.mdwn
@@ -0,0 +1,150 @@
+[[!meta title="Converting Debian packaging from bzr to git"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2009/01/08_debian_bzr_to_git/"]]
+[[!meta date="2009-01-08T00:50:11+0000"]]
+[[!meta copyright="Copyright © 2009 Simon McVittie"]]
+
+I recently converted most of the Debian packaging for Telepathy and related
+projects from bzr to git, while changing the repository contents from just
+the debian/ directory to the whole source tree. Here's the recipe, using the
+latest one to be converted (pymsn) as an example.
+
+## Create a repository
+
+* mkdir pymsn
+
+* cd pymsn
+
+* git init
+
+## Mass tarball import
+
+* download all the tarballs into ../tarballs
+
+* rename all the tarballs to *.orig.tar.gz:
+
+        rename 's/^pymsn-/pymsn_/' *.tar.gz
+	rename 's/\.tar\.gz$/.orig.tar.gz/' *.tar.gz
+
+* use `git-import-orig` to import them:
+
+	cd ../pymsn
+        ls ../tarballs/pymsn_*.orig.tar.gz
+        for v in 0.2 0.2.1 0.2.2 0.3.0 0.3.1 0.3.2 0.3.3; do \
+	git-import-orig --no-merge --no-dch --pristine-tar \
+	    -u $v ../tarballs/pymsn_$v.orig.tar.gz; done
+
+* throw away the resulting `master` branch in favour of using one we convert
+  from bzr later:
+
+        git checkout upstream
+        git branch -D master
+
+## Converting the Debian packaging
+
+This has the slight complication that in some (but not all) of the bzr commits,
+the repository contained only the contents of the debian directory, in the
+root of the repository. So, I needed to rewrite history, with this script:
+
+    #!/bin/sh
+    # index-filter.sh
+    if git ls-files -s | grep debian; then
+        :
+    else
+        git ls-files -s |
+            sed -e "s-\t-&debian/-" |
+            GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
+        mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE
+    fi
+
+
+* Download unstable and experimental packaging into ../pymsn-experimental
+  and ../pymsn-unstable
+
+* Use bzr-fast-export and git-fast-import to import the two branches:
+
+        ~/.bazaar/plugins/fastimport/exporters/bzr-fast-export.py \
+            ../pymsn-unstable | git fast-import
+
+        git branch -m master debian-lenny
+
+        ~/.bazaar/plugins/fastimport/exporters/bzr-fast-export.py \
+            ../pymsn-experimental | git fast-import
+
+        git branch -m master debian
+
+	git branch -D tmp
+
+* Rewrite history so changelog, control etc. are consistently inside a debian
+  directory, with the script shown above:
+
+        git filter-branch --index-filter $(pwd)/../index-filter.sh debian-lenny
+        rm -r .git/refs/original
+
+        git filter-branch --index-filter $(pwd)/../index-filter.sh debian
+        rm -r .git/refs/original
+
+* Merge the appropriate upstream versions into each branch:
+
+        git checkout debian
+	git merge upstream/0.3.3
+	vim debian/control        # and change Vcs-Bzr to Vcs-Git
+	dch "Move packaging to git"
+	debcommit -a
+
+        git checkout debian-lenny
+	git merge upstream/0.3.1
+	vim debian/control        # and change Vcs-Bzr to Vcs-Git
+	dch "Move packaging to git"
+	debcommit -a
+
+* Rescue Debian patches and put them on a debian-patches branch, which is
+  rebased with each upstream release:
+
+	# there aren't any patches in the debian branch at the moment
+        git branch debian-patches upstream/0.3.3
+
+	# but there is one in the debian-lenny branch
+        git branch debian-lenny-patches upstream/0.3.1
+	git checkout debian-lenny
+	cp debian/patches/00-fix-dns-resolution.diff ..
+	git checkout debian-lenny-patches
+	patch -p1 < ../00-fix-dns-resolution.diff
+	git commit -a
+
+* Make a repository on alioth:
+
+        # on alioth
+        cd /git/pkg-telepathy
+	GIT_DIR=pymsn.git git init --bare --shared
+	GIT_DIR=pymsn.git git config hooks.mailinglist ...
+	vim pymsn.git/description
+
+* Push to the repository:
+
+	git gc --aggressive
+	git remote add origin git+ssh://git.debian.org/git/pkg-telepathy/pymsn.git
+	git push --all
+
+* Do some more setup after the initial push:
+
+	# on alioth
+	cat > pymsn.git/hooks/post-receive <<EOF
+	#!/bin/sh
+	exec /usr/local/bin/git-commit-notice
+	EOF
+	chmod +x pymsn.git/hooks/post-receive
+	GIT_DIR=pymsn.git git symbolic-ref HEAD refs/heads/debian
+
+* Mark the old repositories as no longer used:
+
+        cd ../pymsn-unstable
+	dch $'This repository is no longer used, instead please use git:\n'\
+	"git://git.debian.org/git/pkg-telepathy/pymsn.git" -c changelog
+	debcommit -c changelog
+	bzr push
+        cd ../pymsn-experimental
+	dch $'This repository is no longer used, instead please use git:\n'\
+	"git://git.debian.org/git/pkg-telepathy/pymsn.git" -c changelog
+	debcommit -c changelog
+	bzr push
+	cd ../pymsn

Enable actions on blog posts
diff --git a/index.mdwn b/index.mdwn
index 195e3de..cf22138 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -9,7 +9,7 @@ This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
 [[!inline pages="(2009/* or 2008/*) and copyright(*) and !*/Discussion"
-  show="5"
+  show="5" actions="yes"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]
 

switch idp again, *sigh*
diff --git a/index.mdwn b/index.mdwn
index f8a3d0a..195e3de 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -2,8 +2,8 @@
 [[!meta author="Simon McVittie"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
 [[!meta permalink="http://smcv.pseudorandom.co.uk/"]]
-[[!meta openid="http://smcv.myopenid.com/"
-  server="http://www.myopenid.com/server/"]]
+[[!meta openid="https://login.launchpad.net/+id/h7ezLtW"
+  server="https://login.launchpad.net/+openid"]]
 
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)

Fix typos
diff --git a/2008/04/16/tp-svc.mdwn b/2008/04/16/tp-svc.mdwn
index 8f42764..2c8bbf2 100644
--- a/2008/04/16/tp-svc.mdwn
+++ b/2008/04/16/tp-svc.mdwn
@@ -9,9 +9,10 @@
 *(Part 1 of an ongoing series: shiny things in telepathy-glib)*
 
 > `16:46 < epmf> tp-glib is made of magic`
+>
 > -- `#telepathy`, 2008-04-15
 
-Rob_ pointed out today that I'd been promising to blog about
+[Rob] pointed out today that I'd been promising to blog about
 [telepathy-glib] for several months and still haven't done so. I think
 there's too much to cover in one blog post, so I'll start with the
 oldest part - implementing a service (typically a Telepathy connection

only include 5 blog posts on planets; have a non-Atom archive for the rest
Also future-proof pagespecs slightly.
diff --git a/index.mdwn b/index.mdwn
index f15dec9..f8a3d0a 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -8,10 +8,16 @@
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
 
-[[!inline pages="2008/* and copyright(*) and !*/Discussion"
+[[!inline pages="(2009/* or 2008/*) and copyright(*) and !*/Discussion"
+  show="5"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
   description="Simon McVittie's software development blog"]]
 
+Older posts:
+
+[[!inline pages="(2009/* or 2008/*) and copyright(*) and !*/Discussion"
+  skip="5" atom="no" archive="yes"]]
+
 ----
 
-This wiki is powered by [ikiwiki](http://ikiwiki.info/).
+This blog is powered by [ikiwiki](http://ikiwiki.info/).

translate reST content into Markdown
diff --git a/2008/01/20/xrandr.mdwn b/2008/01/20/xrandr.mdwn
new file mode 100644
index 0000000..a44a265
--- /dev/null
+++ b/2008/01/20/xrandr.mdwn
@@ -0,0 +1,38 @@
+[[!meta title="A magical xrandr incantation"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2007/01/20/xrandr/"]]
+[[!meta date="2008-01-20T17:23:13Z"]]
+[[!meta atom.entry.updated="2008-01-20T17:23:13Z"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+
+Here's a handy incantation I use with the Intel X.org graphics driver
+on my laptop.
+
+Put this script somewhere convenient::
+
+    #!/bin/sh
+    if xrandr | grep '^VGA connected' >/dev/null
+    then
+        #echo "VGA connected"
+        xrandr --output VGA --above LVDS --auto
+        xrandr --output LVDS --auto
+    else
+        #echo "VGA not connected"
+        xrandr --auto
+    fi 2>&1 | logger -t xrandr-hotkey
+
+and bind it to your "switch video mode" key, e.g. Fn+F7 on my Thinkpad
+X60s. For instance, I run [xbindkeys], so I saved it as `autoxrandr` and
+put this in `~/xbindkeysrc`:
+
+    "exec /home/smcv/bin/autoxrandr"
+        XF86Display
+
+Now if you press the "switch video mode" key with a monitor plugged in,
+you'll get the external monitor appearing above the laptop panel (my
+preferred configuration - I've balanced my monitor on an N800 box to get
+the bottom of the screen level with the top of my laptop's screen).
+If you press that key again after unplugging the VGA cable, the laptop
+will turn off the VGA output and pull all the windows onto the built-in
+screen.
+
+[xbindkeys]: http://packages.debian.org/xbindkeys
diff --git a/2008/01/20/xrandr.rst b/2008/01/20/xrandr.rst
deleted file mode 100644
index 6fe58a6..0000000
--- a/2008/01/20/xrandr.rst
+++ /dev/null
@@ -1,42 +0,0 @@
-[[!meta title="A magical xrandr incantation"]]
-[[!meta guid="http://smcv.pseudorandom.co.uk/2007/01/20/xrandr/"]]
-[[!meta date="2008-01-20T17:23:13Z"]]
-[[!meta atom.entry.updated="2008-01-20T17:23:13Z"]]
-[[!meta copyright="Copyright © 2008 Simon McVittie"]]
-
-.. class:: atom-body
-
-    Here's a handy incantation I use with the Intel X.org graphics driver
-    on my laptop.
-
-    Put this script somewhere convenient::
-
-        #!/bin/sh
-        if xrandr | grep '^VGA connected' >/dev/null
-        then
-            #echo "VGA connected"
-            xrandr --output VGA --above LVDS --auto
-            xrandr --output LVDS --auto
-        else
-            #echo "VGA not connected"
-            xrandr --auto
-        fi 2>&1 | logger -t xrandr-hotkey
-
-    and bind it to your "switch video mode" key, e.g. Fn+F7 on my Thinkpad
-    X60s. For instance, I run xbindkeys_, so I saved it as ``autoxrandr`` and
-    put this in ~/xbindkeysrc::
-
-        "exec /home/smcv/bin/autoxrandr"
-            XF86Display
-
-    Now if you press the "switch video mode" key with a monitor plugged in,
-    you'll get the external monitor appearing above the laptop panel (my
-    preferred configuration - I've balanced my monitor on an N800 box to get
-    the bottom of the screen level with the top of my laptop's screen).
-    If you press that key again after unplugging the VGA cable, the laptop
-    will turn off the VGA output and pull all the windows onto the built-in
-    screen.
-
-    .. _xbindkeys: http://packages.debian.org/xbindkeys
-..
-  vim: set sw=4 sts=4 et:
diff --git a/2008/04/01/codegen.mdwn b/2008/04/01/codegen.mdwn
new file mode 100644
index 0000000..5519f36
--- /dev/null
+++ b/2008/04/01/codegen.mdwn
@@ -0,0 +1,16 @@
+[[!meta title="Here's how it works"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/01/codegen/"]]
+[[!meta date="2008-04-01T18:21:06Z"]]
+[[!meta atom.entry.updated="2008-04-01T18:21:06Z"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+
+[Daf] recently described a large part of my job, in diagrammatic form:
+
+<img src="/2008/04/generation.png"
+    alt="The secret Collabora code-generation process"
+    width="495"
+    height="700" />
+
+([source](http://people.collabora.co.uk/~daf/))
+
+[daf]: http://dgh.livejournal.com/
diff --git a/2008/04/01/codegen.rst b/2008/04/01/codegen.rst
deleted file mode 100644
index a76aaf8..0000000
--- a/2008/04/01/codegen.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-[[!meta title="Here's how it works"]]
-[[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/01/codegen/"]]
-[[!meta date="2008-04-01T18:21:06Z"]]
-[[!meta atom.entry.updated="2008-04-01T18:21:06Z"]]
-[[!meta copyright="Copyright © 2008 Simon McVittie"]]
-
-.. class:: atom-body
-
-    Daf_ recently described a large part of my job, in diagrammatic form:
-
-    .. image:: /2008/04/generation.png
-        :alt: The secret Collabora code-generation process
-        :width: 495
-        :height: 700
-
-    (`source`_)
-
-    .. _daf: http://dgh.livejournal.com/
-    .. _source: http://people.collabora.co.uk/~daf/
-..
-  vim: set sw=4 sts=4 et:
diff --git a/2008/04/16/tp-svc.mdwn b/2008/04/16/tp-svc.mdwn
new file mode 100644
index 0000000..8f42764
--- /dev/null
+++ b/2008/04/16/tp-svc.mdwn
@@ -0,0 +1,203 @@
+[[!meta title="Implementing D-Bus services with telepathy-glib"]]
+[[!meta description="Implementing services with auto-generated GInterfaces"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/16/tp-svc/"]]
+[[!meta date="2008-04-16T20:36:52Z"]]
+[[!meta atom.entry.updated="2008-04-16T22:07:52Z"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+[[!tag smcv.pseudorandom.co.uk]]
+
+*(Part 1 of an ongoing series: shiny things in telepathy-glib)*
+
+> `16:46 < epmf> tp-glib is made of magic`
+> -- `#telepathy`, 2008-04-15
+
+Rob_ pointed out today that I'd been promising to blog about
+[telepathy-glib] for several months and still haven't done so. I think
+there's too much to cover in one blog post, so I'll start with the
+oldest part - implementing a service (typically a Telepathy connection
+manager).
+
+While telepathy-glib is (obviously) intended for Telepathy
+implementors, I think the ideas we've been implementing are likely
+to be useful for any D-Bus API, particularly flexible/complex APIs
+where an object implements many interfaces.
+
+## Introduction to telepathy-glib
+
+telepathy-glib started out as a collection of code extracted
+from our XMPP connection manager, telepathy-gabble, but at
+some point it grew beyond that into a wrapper around/partial
+replacement for dbus-glib. We've been quite pleased with it,
+really :-)
+
+My first major round of work on telepathy-glib, during the first half of
+2007, was to split it out from telepathy-gabble (versions up to 0.5.9
+were released as part of Gabble 0.5.x tarballs, in fact), leading to
+the release of the 0.6.x stable branch in late September.
+
+This was very helpful for implementing connection managers -
+Salut, Idle and telepathy-sofiasip (our connection managers for
+link-local XMPP, IRC and SIP) all started off by forking/cargo-culting from
+Gabble, and achieved huge code reductions by porting
+to telepathy-glib. Also, [Will Thompson] used it in his Summer of
+Code project, telepathy-haze, to go from nothing to a working
+and useful Telepathy implementation based on [libpurple] in a
+matter of a few months.
+
+The second major round of work, which I'll discuss in a later
+article, added client code to telepathy-glib, obsoleting
+the older/worse libtelepathy and allowing client programs
+like Empathy and telepathy-stream-engine to be written using
+telepathy-glib. In the process, I accidentally reinvented
+DBusGProxy :-) More details to come later!
+

(Diff truncated)
Blog post: why you shouldn't block on D-Bus calls
diff --git a/2008/11.mdwn b/2008/11.mdwn
new file mode 100644
index 0000000..2f3e07f
--- /dev/null
+++ b/2008/11.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="November 2008"]]
+[[!map pages="2008/11/* and copyright(*)" show=title]]
diff --git a/2008/11/nonblocking.mdwn b/2008/11/nonblocking.mdwn
new file mode 100644
index 0000000..229a08f
--- /dev/null
+++ b/2008/11/nonblocking.mdwn
@@ -0,0 +1,116 @@
+[[!meta title="Why you shouldn't block on D-Bus calls"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+[[!meta date="2008-11-24T17:05:06+0000"]]
+[[!meta guid="urn:uuid:46dd715c-58bf-485a-9431-9be18cc58300"]]
+
+I've found myself writing this several times recently in the context
+of Telepathy, so I thought I'd make a blog post that I can refer people to.
+
+D-Bus is defined (by [the wire protocol spec][dbus-spec])
+to be an asynchronous message-passing system, and [libdbus][] behaves
+accordingly; there are no
+blocking calls at the wire protocol level. However, libdbus provides
+a "blocking" API (`dbus_do_something_and_block`), via a mechanism I'll
+refer to as "pseudo-blocking" for the purposes of this post. Most D-Bus
+bindings (at least [dbus-glib][], [dbus-python][] and [QtDBus][]) expose this
+pseudo-blocking behaviour to library users.
+
+[dbus-spec]: http://dbus.freedesktop.org/doc/dbus-specification.html
+    "D-Bus Specification"
+[libdbus]: http://cgit.freedesktop.org/dbus/dbus/
+    "D-Bus reference implementation"
+[dbus-glib]: http://cgit.freedesktop.org/dbus/dbus-glib/
+    "D-Bus GObject bindings"
+[dbus-python]: http://dbus.freedesktop.org/doc/dbus-python/
+    "D-Bus Python bindings"
+[QtDBus]: http://doc.trolltech.com/snapshot/qtdbus.html
+    "Qt D-Bus bindings"
+
+These pseudo-blocking calls work like this:
+
+* send a method call message (call it M)
+* while a reply to M has not been received:
+  * select() or poll() on the D-Bus socket, ignoring all other I/O
+  * whenever a whole message has been received:
+    * check whether the message is a reply to M
+    * if it is (call it R), stop
+    * if it is not, put it on the incoming message queue
+
+The messages received between M and R are delivered when the main loop is
+next entered.
+
+This can cause a number of problems:
+
+* Messages are re-ordered: messages received between M and R
+  aren't delivered until after the reply, violating the ordering
+  guarantee that the D-Bus daemon usually provides.
+
+  (This causes practical problems if a signal indicating object destruction is
+  delayed - the client gets a method reply "UnknownMethod", has to guess
+  that this is because the object has vanished, and can't know why it vanished
+  until the signal indicating its destruction arrives with more details.)
+
+* The client is completely unresponsive until the service replies -
+  if the service has somehow got wedged (e.g. telepathy-gabble is meant
+  to be purely non-blocking and asynchronous, but there are cases where
+  it will do blocking I/O on SSL connections due to Loudmouth bugs), the
+  client will be unresponsive for (by default) 25 seconds until the call
+  times out.
+
+  (Clients shouldn't crash or lock up, whatever happens to the services
+  they depend on.)
+
+* The client can't parallelize calls - if a signal (e.g. an incoming
+  Text message in Telepathy) causes method calls to be made, a client
+  that uses pseudo-blocking calls can't even *start* processing the next
+  message until those method calls return
+
+* If two processes make pseudo-blocking calls on each other, deadlock
+  occurs. This is particularly tricky in the presence of a plugin
+  architecture and shared D-Bus connections - a plugin that "knows" it's a
+  client and not a service, and a plugin in the same process that "knows"
+  it's a service and not a client, can end up sharing a connection,
+  resulting in a process that is both a service and a client (and hence
+  deadlock-prone).
+
+  (We've seen this happen in the OLPC Sugar environment and on Nokia
+  internet tablets; it's not just a theoretical concern.)
+
+As a result, telepathy-glib's code generation mechanism does not generate
+any pseudo-blocking code. There are several alternative modes of operation
+that we do support:
+
+* Fully asynchronous: call a method now, pass it a callback, get
+  your callback called from the main loop later.
+  This can be awkward to program with, but is the only way forward
+  for most non-trivial projects.
+
+* Re-entrant main loop: re-enter the main loop, processing all
+  messages (D-Bus, GUI, network, anything), and run it until the reply has
+  been received. This is useful for trivial projects (like telepathy-glib's
+  regression tests), but dangerous for non-trivial projects (like Empathy),
+  and I'm somewhat regretting implementing this.
+
+* Ignoring the reply: when appropriate (it rarely is), you can make an
+  asynchronous call with `callback = NULL` and the reply will be ignored
+  completely
+
+We make a couple of narrowly targeted exceptions to the "no pseudo-blocking"
+policy in internal code, by allowing telepathy-glib internals to make a
+small number of pseudo-blocking method calls to the dbus-daemon (which is
+the one component we can definitely trust to return results promptly).
+
+Here are some examples of the same strategies in other libraries:
+
+* Pseudo-blocking: dbus-python method calls with no special
+  keyword arguments; dbus-glib `dbus_g_proxy_call`;
+  QDBus calls with mode `QDBus::Block`
+
+* Fully asynchronous: dbus-python method calls with `reply_callback` and
+  `error_callback` keyword arguments; dbus-glib `dbus_g_proxy_begin_call`;
+  `QDBusConnection::callWithCallback`
+
+* Re-entrant: QDBus calls with mode `QDBus::BlockWithGui`
+
+* Ignoring reply: dbus-python method calls with `ignore_reply` keyword
+  argument; QDBus calls with mode `QDBus::NoWaitForReply`

Switch IDP to myOpenID
diff --git a/index.mdwn b/index.mdwn
index 0c25450..f15dec9 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -2,8 +2,8 @@
 [[!meta author="Simon McVittie"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
 [[!meta permalink="http://smcv.pseudorandom.co.uk/"]]
-[[!meta openid="http://getopenid.com/smcv/"
-  server="http://getopenid.com/action/authenticate/"]]
+[[!meta openid="http://smcv.myopenid.com/"
+  server="http://www.myopenid.com/server/"]]
 
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)

Blog post: cryptoroot + recovery partition on Debian
diff --git a/2008/09/cryptroot.mdwn b/2008/09/cryptroot.mdwn
new file mode 100644
index 0000000..247475b
--- /dev/null
+++ b/2008/09/cryptroot.mdwn
@@ -0,0 +1,118 @@
+[[!meta title="Encrypted root filesystem on a Debian laptop"]]
+[[!meta date="2008-09-11T16:36:00+0100"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+
+I've been meaning to document this for ages...
+
+My laptop is set up with an encrypted root filesystem using LVM and dmcrypt.
+It also has a small Debian stable system for recovery purposes (I don't have
+a CD drive, so if everything goes horribly wrong, I can't just boot from a
+live CD).
+
+Here's how to set up something similar:
+
+## Step 1. Set up the recovery system
+
+Start the Debian lenny (beta) installer as usual. (I originally used etch,
+but these instructions are for lenny - either should work.)
+
+When you get to "Partition disks", choose "Manual".
+
+Here's the partitioning scheme to use:
+
+* main partition for LVM, taking up the whole disk minus 1GB or so. select
+  "Do not use", for now
+
+* 1GB recovery partition at the end of the disk (this will also be the main
+  system's /boot, since /boot needs to be unencrypted anyway).
+  Use the defaults: ext3 mounted at /.
+
+Finish partitioning and write changes to disk, and wait for the base system
+to install.
+
+Say yes to installing Grub to the MBR for now (it might be possible to do
+the install more cleanly by installing Grub to the recovery partition's boot
+sector instead - I haven't tested that).
+
+Reboot into the freshly installed recovery system and satisfy yourself that
+it works.
+
+## Step 2. Set up the main system
+
+Now boot the Debian installer again. This time it's for your installed
+system.
+
+At the "Partition disks" stage, choose "Manual" again. Select the main
+partition and choose "Use as: physical volume for encryption".
+
+Next select "Configure encrypted volumes". Your main partition will now be
+randomized - this is slow - and some time later you'll be asked for a
+passphrase. You'll have to type this in at each boot.
+
+Select the contents of the "disk" Encrypted volume (hda1_crypt)
+and choose Use as: physical volume for LVM.
+
+Now "Configure the Logical Volume Manager" and create a Volume Group.
+I always use the laptop's hostname as the VG name (this reduces confusion
+if you ever plug the disk into another machine for disaster recovery).
+
+Create a Logical Volume called swap, the size you want your swap space
+to be. If you plan to use suspend-to-disk, this needs to be at least as
+large as your RAM.
+
+Create a Logical Volume called root, for the root filesystem. If you want
+separate "partitions" for things like /home, now is a good time to create
+them too; if you want to use my schroot howto, leave some unallocated
+space in the VG for that.
+
+Set your swap LV to be used as a swap area, and your root LV to be used
+as ext3 mounted at `/`. If you wanted extra LVs, set them up too.
+
+Also set your recovery partition to be used as ext3, mounted on /boot,
+and not reformatted.
+
+It should now look something like this (smcvcrypt is the name of
+a KVM virtual machine in which I've been testing these instructions, normally
+you'd have the laptop's hostname there).
+
+![Screenshot from d-i](/2008/09/cryptroot/partitions.png)
+
+Proceed with the installation.
+
+Install Grub to the MBR - this will temporarily make the recovery system
+unbootable, but *shrug* never mind. Finish the installation and reboot into
+your new main system.
+
+## Step 3. Make them dual-boot
+
+Within the main system your recovery system is also visible, at /boot.
+Bind-mount /dev onto /boot/dev, chroot into /boot, and run
+"update-grub /dev/hda2", where hda2 is the partition where the recovery
+partition is. Leave the chroot.
+
+Edit /boot/grub/menu.lst and put this right at the end:
+
+    title Go to recovery system
+    root (hd0,1)
+    chainloader +1
+
+(Replace (hd0,1) with what Grub thinks the recovery partition is - the second
+number is the partition number starting from 0, so /dev/hda5 would be (hd0,4)
+and so on.)
+
+Also edit /boot/boot/grub/menu.lst and put this right at the end:
+
+    title Back to main system
+    root (hd0)
+    chainloader +1
+
+Also, still in /boot/boot/grub/menu.lst, go to the top of the file and
+change the colour scheme to something else (I used a red background) to
+indicate that this boot menu is for the recovery system.
+
+Reboot and try it out. You should now have an extra boot menu option,
+"Recovery system". Selecting it will switch to the recovery system's
+boot menu, which has an option to switch back, and so on. Each boot menu
+also has some entries for kernels, any of which will boot with the
+appropriate root filesystem (encrypted root for the main system,
+unencrypted for the recovery system). Success!

Blog post: Compiling against uninstalled versions of libraries
diff --git a/2008/09/pc-uninstalled.mdwn b/2008/09/pc-uninstalled.mdwn
new file mode 100644
index 0000000..52a7784
--- /dev/null
+++ b/2008/09/pc-uninstalled.mdwn
@@ -0,0 +1,78 @@
+[[!meta title="Compiling against uninstalled versions of libraries"]]
+[[!meta date="2008-09-03T18:30:54+0100"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+
+Developers seem to do a lot of fighting with bleeding-edge libraries installed
+in a --prefix, so I thought I'd share how I develop telepathy-glib (a library)
+and telepathy-gabble (a program using that library).
+
+~/Collabora/telepathy/tpglib on my laptop is a git clone of
+telepathy-glib.git, branched using the process I documented on
+<http://telepathy.freedesktop.org/wiki/Git>, which is basically:
+
+* clone the upstream repository
+  (git+ssh://git.collabora.co.uk/git/telepathy-glib.git in this case)
+  into your home directory on the server
+  (git+ssh://people.collabora.co.uk/home/smcv/public_html/git/telepathy-glib-smcv.git in this case)
+* clone *that* onto your laptop
+* on your laptop, add "upstream" as a remote, tracking the upstream repository
+* this reduces mistakes, because "git push" pushes to origin (which is in my
+  home directory) for review, and "git push upstream" is necessary when I
+  actually want to commit to the upstream repository
+
+~/Collabora/telepathy/gabble is a git clone of telepathy-gabble.git, using the
+same process.
+
+In my Gabble checkout, I used to configure like this:
+
+    cd ~/Collabora/telepathy/gabble
+    TP_GLIB_CFLAGS="-I${HOME}/Collabora/telepathy/tpglib" \
+    TP_GLIB_LIBS="${HOME}/Collabora/telepathy/tpglib/telepathy-glib/libtelepathy-glib.la" \
+    sh ./autogen.sh
+
+This would make libtool link Gabble against the copy of telepathy-glib built by
+my bleeding-edge git checkout, without ever needing to install it.
+This allowed me to try out my latest telepathy-glib changes with
+Gabble's more extensive regression tests, which was a great win.
+
+It also meant I could develop Gabble branches that required a not-yet-released
+telepathy-glib, and all without touching my system copy of telepathy-glib
+(the one I use to run Empathy and talk to people - which is the packaged
+version from Debian unstable or experimental).
+
+The reason I could do this is that I laid out the telepathy-glib source tree in
+The Right Way™, which is: if a header is designed to be used via
+`#include <my-library/foo.h>`, then it goes in a `my-library/` directory
+in the source tree, and includes other headers (even from the same project)
+with `#include <my-library/other.h>`.
+
+This means you can just add the top directory of the source tree to your
+include path (which automake does by default) and the right thing will happen.
+
+(Actually, this is a slight simplification of the truth: because telepathy-glib
+contains generated headers, you have to add the top directory of the *build*
+tree to your include path too, if you want to support out-of-tree builds.
+Which, of course, you do.)
+
+Other projects that do this correctly include GLib and Avahi. Avahi is a
+particularly interesting example because it has numerous libraries in the same
+tarball (including avahi-common, avahi-core, avahi-glib and avahi-gobject,
+which form a dependency chain).
+
+Projects that *don't* do this correctly include telepathy-mission-control
+(which is on my hit list for further swamp-draining) and libtelepathy (which
+is obsolete).
+
+Today I committed a patch to telepathy-glib, inspired by GStreamer, to
+[generate telepathy-glib-uninstalled.pc](http://git.collabora.co.uk/?p=user/smcv/telepathy-glib-smcv.git;a=commitdiff;h=ea53d448e9d014936be66b5e3d22080decab1347).
+The presence of this patch simplifies the process further, to:
+
+    PKG_CONFIG_PATH=$HOME/Collabora/tpglib/telepathy-glib sh ./autogen.sh
+
+This has the same benefits as setting TP_GLIB_CFLAGS and TP_GLIB_LIBS,
+but is easier to remember, and is more future-proof against changes to
+telepathy-glib.
+
+It only works because pkg-config has a special case for this situation -
+if you ask for the package "foo", pkg-config will always look for
+foo-uninstalled.pc before foo.pc.

2008/09/eoc: remove repeated lines
diff --git a/2008/09/eoc.mdwn b/2008/09/eoc.mdwn
index 0f1c303..ec8b1d4 100644
--- a/2008/09/eoc.mdwn
+++ b/2008/09/eoc.mdwn
@@ -24,8 +24,6 @@ Postfix than he is at making blog posts, so I get to be the one posting this...
                       >/etc/postfix/list_transports
     09:59 <@Robot101> giving list_transports like this:
     09:59 <@Robot101> /^test(-[^@]*)?@lists.collabora.co.uk$/ eoc
-    09:59 <@Robot101> /^test(-[^@]*)?@lists.collabora.co.uk$/ eoc
-    09:59 <@Robot101> /^test(-[^@]*)?@lists.collabora.co.uk$/ eoc
     09:59 <@Robot101> (thanks to smcv for assistance with regexp-generation regexp)
     ...
     10:01 <@wjt> ten points for using the best -named mlm

Blog post: Integrating Enemies of Carlotta with Postfix
diff --git a/2008/09.mdwn b/2008/09.mdwn
new file mode 100644
index 0000000..9c94884
--- /dev/null
+++ b/2008/09.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="September 2008"]]
+[[!map pages="2008/09/* and copyright(*)" show=title]]
diff --git a/2008/09/eoc.mdwn b/2008/09/eoc.mdwn
new file mode 100644
index 0000000..0f1c303
--- /dev/null
+++ b/2008/09/eoc.mdwn
@@ -0,0 +1,33 @@
+[[!meta title="Integrating Enemies of Carlotta with Postfix"]]
+[[!meta date="2008-09-02T11:48:43+0300"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie / Rob McQueen"]]
+
+From the "doing sysadmin over wobbly 3G while waiting for our plane to be
+allowed to take off" department comes this bit of mailing list setup.
+By his own admission, [Rob](http://www.robot101.net/) is better at configuring
+Postfix than he is at making blog posts, so I get to be the one posting this...
+
+    09:58 <@Robot101> my postfix -> eoc integration is basically ninja, if I might 
+                      say so myself
+    09:58 <@Robot101> so, an eoc transport in master.cf:
+    09:58 <@Robot101> eoc       unix  -       n       n       -       10      pipe 
+                      user=list argv=/usr/bin/enemies-of-carlotta --quiet 
+                      --incoming --sender=${sender} --recipient=${recipient}
+    09:59 <@Robot101> then in main.cf:
+    09:59 <@Robot101> eoc_destination_recipient_limit = 1
+    09:59 <@Robot101> virtual_mailbox_domains = lists.collabora.co.uk
+    09:59 <@Robot101> virtual_mailbox_maps = pcre:/etc/postfix/list_transports
+    09:59 <@Robot101> transport_maps = pcre:/etc/postfix/list_transports
+    09:59 <@Robot101> then a script/cron:
+    09:59 <@Robot101> su -c "enemies-of-carlotta --show-lists" list | sed 
+                      's,\(.*\)@\(.*\),/^\1(-[^@]*)?@\2$/ eoc,' 
+                      >/etc/postfix/list_transports
+    09:59 <@Robot101> giving list_transports like this:
+    09:59 <@Robot101> /^test(-[^@]*)?@lists.collabora.co.uk$/ eoc
+    09:59 <@Robot101> /^test(-[^@]*)?@lists.collabora.co.uk$/ eoc
+    09:59 <@Robot101> /^test(-[^@]*)?@lists.collabora.co.uk$/ eoc
+    09:59 <@Robot101> (thanks to smcv for assistance with regexp-generation regexp)
+    ...
+    10:01 <@wjt> ten points for using the best -named mlm
+    10:01 <@Robot101> 2000 points for not having a mailing list system held 
+                      together with procmail, shell, duct tape, gash and string

Blog post: speeding up builds with ccache and icecc
diff --git a/2008/08.mdwn b/2008/08.mdwn
new file mode 100644
index 0000000..db86288
--- /dev/null
+++ b/2008/08.mdwn
@@ -0,0 +1,2 @@
+[[!meta title="August 2008"]]
+[[!map pages="2008/08/* and copyright(*)" show=title]]
diff --git a/2008/08/collaboratively.mdwn b/2008/08/collaboratively.mdwn
new file mode 100644
index 0000000..1840570
--- /dev/null
+++ b/2008/08/collaboratively.mdwn
@@ -0,0 +1,41 @@
+[[!meta title="Speeding up builds with ccache and icecc"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2008/08/collaboratively/"]]
+[[!meta date="2008-08-05T12:44:01+0100"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+
+Here's a script I use to speed up compilation at work. Since I work at
+[Collabora](http://www.collabora.co.uk/), I call it `collaboratively`.
+It's a prefix to a command (used in the same way as sudo or nice) which sets
+up icecc ([Icecream](http://en.opensuse.org/Icecream)) and ccache to work
+nicely together.
+
+    #!/bin/sh
+    # ~/bin/collaboratively
+    # Typical usage: collaboratively make check
+    PATH=/usr/lib/ccache:/usr/lib/icecc/bin$(echo :$PATH | sed -e s@:/usr/lib/ccache@@g)
+    export PATH
+    MAKEFLAGS='-j -l3'
+    export MAKEFLAGS
+    exec "$@"
+
+Some more explanation of what it does:
+
+* First, I want the gcc wrappers (actually symlinks to ccache) in
+  /usr/lib/ccache to be invoked. This uses ccache to make sure I don't
+  actually recompile source code that hasn't changed.
+
+* Next, I want to use icecc, which distributes builds around the office.
+  We run an icecc scheduler on the office server, which also contributes
+  two CPU cores and lots of RAM to the compilation effort.
+
+* To prevent infinite recursion between icecc and ccache, I have to make sure
+  ccache *isn't* in my `$PATH` for a second time! My `bash` and `zsh` dotfiles
+  automatically set up ccache, so in practice it does need editing out.
+
+* When distributing builds, `make` should be parallelizing as many compiles as
+  feasible - I use the flags `-j -l3` to run an unlimited number of parallel
+  compilation processes, but stop when the load average reaches 3 (the number
+  of CPU cores I have, plus 1, seems a reasonable maximum load-average).
+
+`apt-get install icecc-monitor` and run `icemon` to see whether this is all
+working - if it is, you should see compile jobs going off to other hosts.

Improve sitemap pages
diff --git a/2008.mdwn b/2008.mdwn
index 8b83870..767a4ac 100644
--- a/2008.mdwn
+++ b/2008.mdwn
@@ -1 +1 @@
-[[!map pages="./* and copyright(*)" show=title]]
+[[!map pages="2008/* and copyright(*)" show=title]]
diff --git a/2008/01.mdwn b/2008/01.mdwn
index 8b83870..7fba4df 100644
--- a/2008/01.mdwn
+++ b/2008/01.mdwn
@@ -1 +1,2 @@
-[[!map pages="./* and copyright(*)" show=title]]
+[[!meta title="January 2008"]]
+[[!map pages="2008/01/* and copyright(*)" show=title]]
diff --git a/2008/04.mdwn b/2008/04.mdwn
index 8b83870..e635039 100644
--- a/2008/04.mdwn
+++ b/2008/04.mdwn
@@ -1 +1,2 @@
-[[!map pages="./* and copyright(*)" show=title]]
+[[!meta title="April 2008"]]
+[[!map pages="2008/04/* and copyright(*)" show=title]]
diff --git a/2008/05.mdwn b/2008/05.mdwn
index 8b83870..a7f710a 100644
--- a/2008/05.mdwn
+++ b/2008/05.mdwn
@@ -1 +1,2 @@
-[[!map pages="./* and copyright(*)" show=title]]
+[[!meta title="May 2008"]]
+[[!map pages="2008/05/* and copyright(*)" show=title]]

reinstate my openid
diff --git a/index.mdwn b/index.mdwn
index 06eece3..0c25450 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -2,6 +2,8 @@
 [[!meta author="Simon McVittie"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
 [[!meta permalink="http://smcv.pseudorandom.co.uk/"]]
+[[!meta openid="http://getopenid.com/smcv/"
+  server="http://getopenid.com/action/authenticate/"]]
 
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)

Temporarily set a permalink on index to avoid index.html visibility in atom feed
diff --git a/index.mdwn b/index.mdwn
index 908ebc8..06eece3 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -1,6 +1,7 @@
 [[!meta title="Background noise"]]
 [[!meta author="Simon McVittie"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
+[[!meta permalink="http://smcv.pseudorandom.co.uk/"]]
 
 This is Simon McVittie's software development blog. Main site:
   [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)

Add tp-svc article (from pseudorandom.co.uk, should be pulled in via aggregate eventually
diff --git a/2008/04/16.mdwn b/2008/04/16.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/04/16.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]
diff --git a/2008/04/16/tp-svc.rst b/2008/04/16/tp-svc.rst
new file mode 100644
index 0000000..e125b66
--- /dev/null
+++ b/2008/04/16/tp-svc.rst
@@ -0,0 +1,215 @@
+[[!meta title="Implementing D-Bus services with telepathy-glib"]]
+[[!meta description="Implementing services with auto-generated GInterfaces"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/16/tp-svc/"]]
+[[!meta permalink="http://www.pseudorandom.co.uk/2008/04/16/tp-svc/"]]
+[[!meta date="2008-04-16T20:36:52Z"]]
+[[!meta atom.entry.updated="2008-04-16T22:07:52Z"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
+
+*(Part 1 of an ongoing series: shiny things in telepathy-glib)*
+
+.. class:: atom-summary
+
+        ..
+
+                ``16:46 < epmf> tp-glib is made of magic``
+
+                -- #telepathy, 2008-04-15
+
+        Rob_ pointed out today that I'd been promising to blog about
+        telepathy-glib_ for several months and still haven't done so. I think
+        there's too much to cover in one blog post, so I'll start with the
+        oldest part - implementing a service (typically a Telepathy connection
+        manager).
+
+        While telepathy-glib is (obviously) intended for Telepathy
+        implementors, I think the ideas we've been implementing are likely
+        to be useful for any D-Bus API, particularly flexible/complex APIs
+        where an object implements many interfaces.
+
+Introduction to telepathy-glib
+==============================
+
+telepathy-glib started out as a collection of code extracted
+from our XMPP connection manager, telepathy-gabble, but at
+some point it grew beyond that into a wrapper around/partial
+replacement for dbus-glib. We've been quite pleased with it,
+really :-)
+
+My first major round of work on telepathy-glib, during the first half of
+2007, was to split it out from telepathy-gabble (versions up to 0.5.9
+were released as part of Gabble 0.5.x tarballs, in fact), leading to
+the release of the 0.6.x stable branch in late September.
+
+This was very helpful for implementing connection managers -
+Salut, Idle and telepathy-sofiasip (our connection managers for
+link-local XMPP, IRC and SIP) all started off by forking/cargo-culting from
+Gabble, and achieved huge code reductions by porting
+to telepathy-glib. Also, `Will Thompson`_ used it in his Summer of
+Code project, telepathy-haze, to go from nothing to a working
+and useful Telepathy implementation based on libpurple_ in a
+matter of a few months.
+
+The second major round of work, which I'll discuss in a later
+article, added client code to telepathy-glib, obsoleting
+the older/worse libtelepathy and allowing client programs
+like Empathy and telepathy-stream-engine to be written using
+telepathy-glib. In the process, I accidentally reinvented
+DBusGProxy :-) More details to come later!
+
+Some background: service-side code generation
+=============================================
+
+.. class:: float-right
+
+        .. figure:: http://smcv.pseudorandom.co.uk/2008/04/generation-300.png
+                :alt: The secret Collabora code-generation process
+                :width: 212
+                :height: 300
+
+                (credit: daf_)
+
+Supporting D-Bus in the GObject world has always involved quite a lot of code
+generation. The core API of dbus-glib is heavily reliant on varargs functions,
+which aren't type-safe and are easy to get wrong.
+
+dbus-glib contains a program called dbus-binding-tool, which is meant to
+generate reasonably sane GObject APIs for D-Bus objects. Unfortunately, it
+seems to be intended to generate a whole GObject at a time.
+
+Early versions of telepathy-gabble used dbus-binding-tool plus a
+script called ``gengobject.py`` to generate API stubs for the exported
+objects; developers then filled in the blanks, and hey presto, we had a
+GObject on D-Bus. This was fine up to a point, but had a couple of major
+drawbacks.
+
+Whenever we changed the D-Bus API (quite common during the early development
+of Telepathy), there was a very laborious and error-prone merging process.
+We ended up with the following process:
+
+* copy the D-Bus introspection XML from the telepathy-spec repository
+  into a directory ``xml/pristine``
+  (actually, the canonical form for the spec was Python for a while, and we
+  had a script that exported a contrived object onto D-Bus and introspected
+  itself to get the XML - but that's another story!)
+
+* preprocess the introspection XML to add the dbus-glib CFunctionName
+  annotation, resulting in a directory ``xml/modified``
+
+* run ``dbus-binding-tool`` and a Python script ``gengobject.py`` to generate
+  C source in ``xml/src``
+
+* three-way-diff the old version of ``xml/src``, the new version of ``xml/src``,
+  and the real C code in ``src`` to create a new version of ``src``
+
+* pray that the diff process hadn't randomly exchanged functions'
+  implementations
+
+* update the resulting code in ``src`` so it worked
+
+* check the whole mess back into darcs
+
+* hope that nobody else had made changes that would result in darcs conflicts
+
+If you haven't yet gathered, this was a bit of a nightmare.
+
+Also, it was very easy to return the wrong thing from a method without
+noticing - because all the APIs were varargs, the compiler didn't notice,
+and the first we'd know about it was a mysterious segfault under certain
+circumstances.
+
+How telepathy-glib fixes code generation
+========================================
+
+telepathy-glib improves on this by taking advantage of this innocuous-looking
+feature in dbus-glib::
+
+        commit 355ef78d98d6fc65715845d56232199162cab12a
+        Author: Steve Frécinaux <steve istique net>
+        Date:   Thu Aug 17 11:48:20 2006 +0200
+
+            Interface support for bindings.
+
+Instead of running dbus-binding-tool or creating GObjects with D-Bus
+interfaces, we put the entire Telepathy spec through
+``glib-ginterface-gen.py``, a distant descendant of Gabble's ``gengobject.py``.
+For each interface in the spec, we generate a GInterface that mirrors the
+D-Bus interface. Any GObject that implements the GInterface automatically
+gets the D-Bus interface if it's exported onto D-Bus.
+
+There are a few non-obvious refinements, though:
+
+* The signature of the method implementation is always in the mode that
+  dbus-glib calls "asynchronous", where the method implementation can either
+  send a reply message before or after it returns.
+
+  For "slow" methods, this is the only thing you can do. For instance, many
+  Telepathy D-Bus methods can't return anything until some TCP round-trips
+  to the server have happened.
+
+  This is also the only thing you can do if you want to extract extra
+  information, like the sender's unique name, from the method-call message
+  (dbus-glib's "synchronous" API doesn't allow this to be done).
+
+  For "fast" methods, sending a reply message before returning is just as
+  easy as using the "synchronous" API (it's just a difference of syntax), and
+  has an API consistent with that of the "slow" methods, making it easier
+  for service authors.
+
+* The layout of the GInterface vtable is private, and (auto-generated)
+  accessor functions are used to fill in implementations. This means our
+  ABI doesn't change just because we re-ordered functions in the spec.
+
+* If no implementation is provided for a method, we just raise an appropriate
+  error (org.freedesktop.Telepathy.Errors.NotImplemented), rather than
+  suffering an assertion failure. This means we can safely add methods to
+  an interface.
+
+* While we're generating code anyway, we generate some static inline wrapper
+  functions which wrap ``dbus_g_method_return()``, to have type-safe method
+  returns. You can easily check that a method replies with correct types, by
+  checking that the implementation of Foo() replies by calling
+  tp_svc_some_interface_return_from_foo().
+
+* Similarly, we generate wrapper functions to emit signals, to get type-safe
+  signal emission.
+
+Not all interfaces are stable enough to be included in telepathy-glib's stable
+API and ABI, so some of our other projects include a copy of the telepathy-glib
+code-generation tools, and generate their own "mini-telepathy-glib"
+(traditionally in a ``/extensions/`` directory) for their
+implementation-specific (drafts of) interfaces. This isn't yet as polished as
+it ought to be (mainly because we don't want to freeze the
+augmented-introspection-XML format that we write the Telepathy spec in, because
+it's rather ad-hoc and hackish in places) but it works quite well in practice.
+
+To see what this looks like in practice, have a look at the examples in
+telepathy-glib_, or at a Telepathy connection manager like telepathy-gabble_.

(Diff truncated)
Make 2008.mdwn the same as the others
diff --git a/2008.mdwn b/2008.mdwn
index 767a4ac..8b83870 100644
--- a/2008.mdwn
+++ b/2008.mdwn
@@ -1 +1 @@
-[[!map pages="2008/* and copyright(*)" show=title]]
+[[!map pages="./* and copyright(*)" show=title]]

Add parent pages
diff --git a/2008.mdwn b/2008.mdwn
new file mode 100644
index 0000000..767a4ac
--- /dev/null
+++ b/2008.mdwn
@@ -0,0 +1 @@
+[[!map pages="2008/* and copyright(*)" show=title]]
diff --git a/2008/01.mdwn b/2008/01.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/01.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]
diff --git a/2008/01/20.mdwn b/2008/01/20.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/01/20.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]
diff --git a/2008/04.mdwn b/2008/04.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/04.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]
diff --git a/2008/04/01.mdwn b/2008/04/01.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/04/01.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]
diff --git a/2008/04/18.mdwn b/2008/04/18.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/04/18.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]
diff --git a/2008/05.mdwn b/2008/05.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/05.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]
diff --git a/2008/05/16.mdwn b/2008/05/16.mdwn
new file mode 100644
index 0000000..8b83870
--- /dev/null
+++ b/2008/05/16.mdwn
@@ -0,0 +1 @@
+[[!map pages="./* and copyright(*)" show=title]]

Shorten title
diff --git a/index.mdwn b/index.mdwn
index cbaa12e..908ebc8 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -1,4 +1,4 @@
-[[!meta title="Scream to the tune of the background noise"]]
+[[!meta title="Background noise"]]
 [[!meta author="Simon McVittie"]]
 [[!meta copyright="Copyright © 2008 Simon McVittie"]]
 

Add a .gitignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b84c806
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/.ikiwiki
+/recentchanges

Fix front page
diff --git a/index.mdwn b/index.mdwn
index 8752c8d..cbaa12e 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -1,12 +1,14 @@
 [[!meta title="Scream to the tune of the background noise"]]
 [[!meta author="Simon McVittie"]]
-[[!meta copyright="Copyright © 2008 Simon McVittie]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
 
-[[!inline pages="./2008/* and !*/Discussion"
+This is Simon McVittie's software development blog. Main site:
+  [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
+
+[[!inline pages="2008/* and copyright(*) and !*/Discussion"
   atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
-  description="Simon McVittie's software development blog"
-  ]]
+  description="Simon McVittie's software development blog"]]
 
 ----
 
-This wiki is powered by [ikiwiki](http://ikiwiki.info).
+This wiki is powered by [ikiwiki](http://ikiwiki.info/).

Add copyright to blog posts; remove permalinks
diff --git a/2008/01/20/xrandr.rst b/2008/01/20/xrandr.rst
index ac30d90..6fe58a6 100644
--- a/2008/01/20/xrandr.rst
+++ b/2008/01/20/xrandr.rst
@@ -2,7 +2,7 @@
 [[!meta guid="http://smcv.pseudorandom.co.uk/2007/01/20/xrandr/"]]
 [[!meta date="2008-01-20T17:23:13Z"]]
 [[!meta atom.entry.updated="2008-01-20T17:23:13Z"]]
-[[!meta permalink="http://smcv.pseudorandom.co.uk/2008/01/20/xrandr/"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
 
 .. class:: atom-body
 
diff --git a/2008/04/01/codegen.rst b/2008/04/01/codegen.rst
index c5d06c8..a76aaf8 100644
--- a/2008/04/01/codegen.rst
+++ b/2008/04/01/codegen.rst
@@ -1,8 +1,8 @@
 [[!meta title="Here's how it works"]]
 [[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/01/codegen/"]]
-[[!meta permalink="http://smcv.pseudorandom.co.uk/2008/04/01/codegen/"]]
 [[!meta date="2008-04-01T18:21:06Z"]]
 [[!meta atom.entry.updated="2008-04-01T18:21:06Z"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
 
 .. class:: atom-body
 
diff --git a/2008/04/18/dd.rst b/2008/04/18/dd.rst
index 851ddbe..c043988 100644
--- a/2008/04/18/dd.rst
+++ b/2008/04/18/dd.rst
@@ -2,6 +2,7 @@
 [[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/18/dd/"]]
 [[!meta date="2008-04-18T15:23:00Z"]]
 [[!meta atom.entry.updated="2008-04-18T15:23:00Z"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
 
 .. class:: atom-body
 
diff --git a/2008/05/16/onaplane.rst b/2008/05/16/onaplane.rst
index c9a33b3..be62da4 100644
--- a/2008/05/16/onaplane.rst
+++ b/2008/05/16/onaplane.rst
@@ -2,7 +2,7 @@
 [[!meta guid="http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/"]]
 [[!meta date="2008-05-19T10:03:00Z"]]
 [[!meta atom.entry.updated="2008-05-19T10:03:00Z"]]
-[[!meta permalink="http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie"]]
 
 .. class:: atom-body
 

Fill in more of the front page
diff --git a/index.mdwn b/index.mdwn
index 5c7c893..8752c8d 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -1,6 +1,11 @@
 [[!meta title="Scream to the tune of the background noise"]]
+[[!meta author="Simon McVittie"]]
+[[!meta copyright="Copyright © 2008 Simon McVittie]]
 
-[[!inline pages="./2008/* and !*/Discussion"]]
+[[!inline pages="./2008/* and !*/Discussion"
+  atom="yes" guid="urn:uuid:0955f57e-4c2c-4614-b791-cf0bfb70f00e"
+  description="Simon McVittie's software development blog"
+  ]]
 
 ----
 

Add an index page
diff --git a/index.mdwn b/index.mdwn
new file mode 100644
index 0000000..5c7c893
--- /dev/null
+++ b/index.mdwn
@@ -0,0 +1,7 @@
+[[!meta title="Scream to the tune of the background noise"]]
+
+[[!inline pages="./2008/* and !*/Discussion"]]
+
+----
+
+This wiki is powered by [ikiwiki](http://ikiwiki.info).

Reformat blog content for ikiwiki
diff --git a/2008/01/20/xrandr.rst b/2008/01/20/xrandr.rst
index 84fbb5b..ac30d90 100644
--- a/2008/01/20/xrandr.rst
+++ b/2008/01/20/xrandr.rst
@@ -1,17 +1,8 @@
-============================
-A magical xrandr incantation
-============================
-
-.. meta::
-    :dcterms.created: 2008-01-20
-    :dcterms.modified: 2008-01-20
-    :atom.entry.id: http://smcv.pseudorandom.co.uk/2007/01/20/xrandr/
-    :atom.entry.published: 2008-01-20T17:23:13Z
-    :atom.entry.updated: 2008-01-20T17:23:13Z
-    :flatland.sites: smcv.pseudorandom.co.uk
-    :flatland.location: /2008/01/20/xrandr/
-.. metalink::
-    :rel=self: http://smcv.pseudorandom.co.uk/2008/01/20/xrandr/
+[[!meta title="A magical xrandr incantation"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2007/01/20/xrandr/"]]
+[[!meta date="2008-01-20T17:23:13Z"]]
+[[!meta atom.entry.updated="2008-01-20T17:23:13Z"]]
+[[!meta permalink="http://smcv.pseudorandom.co.uk/2008/01/20/xrandr/"]]
 
 .. class:: atom-body
 
diff --git a/2008/04/01/codegen.rst b/2008/04/01/codegen.rst
index 47490f6..c5d06c8 100644
--- a/2008/04/01/codegen.rst
+++ b/2008/04/01/codegen.rst
@@ -1,17 +1,8 @@
-===================
-Here's how it works
-===================
-
-.. meta::
-    :dcterms.created: 2008-04-01
-    :dcterms.modified: 2008-04-01
-    :atom.entry.id: http://smcv.pseudorandom.co.uk/2008/04/01/codegen/
-    :atom.entry.published: 2008-04-01T18:21:06Z
-    :atom.entry.updated: 2008-04-01T18:21:06Z
-    :flatland.sites: smcv.pseudorandom.co.uk
-    :flatland.location: /2008/04/01/codegen/
-.. metalink::
-    :rel=self: http://smcv.pseudorandom.co.uk/2008/04/01/codegen/
+[[!meta title="Here's how it works"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/01/codegen/"]]
+[[!meta permalink="http://smcv.pseudorandom.co.uk/2008/04/01/codegen/"]]
+[[!meta date="2008-04-01T18:21:06Z"]]
+[[!meta atom.entry.updated="2008-04-01T18:21:06Z"]]
 
 .. class:: atom-body
 
diff --git a/2008/04/18/dd.rst b/2008/04/18/dd.rst
index 1469dcb..851ddbe 100644
--- a/2008/04/18/dd.rst
+++ b/2008/04/18/dd.rst
@@ -1,15 +1,7 @@
-====
-\\o/
-====
-
-.. meta::
-    :dcterms.created: 2008-04-18
-    :dcterms.modified: 2008-04-18
-    :atom.entry.id: http://smcv.pseudorandom.co.uk/2008/04/18/dd/
-    :atom.entry.published: 2008-04-18T15:23:00Z
-    :atom.entry.updated: 2008-04-18T15:23:00Z
-.. metalink::
-    :rel=self: http://smcv.pseudorandom.co.uk/2008/04/18/dd/
+[[!meta title="\o/"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2008/04/18/dd/"]]
+[[!meta date="2008-04-18T15:23:00Z"]]
+[[!meta atom.entry.updated="2008-04-18T15:23:00Z"]]
 
 .. class:: atom-body
 
diff --git a/2008/05/16/onaplane.rst b/2008/05/16/onaplane.rst
index bfe33d4..c9a33b3 100644
--- a/2008/05/16/onaplane.rst
+++ b/2008/05/16/onaplane.rst
@@ -1,15 +1,8 @@
-=======================
-Spec-writing On A Plane
-=======================
-
-.. meta::
-    :dcterms.created: 2008-05-16
-    :dcterms.modified: 2008-05-19
-    :atom.entry.id: http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/
-    :atom.entry.published: 2008-05-19T10:03:00Z
-    :atom.entry.updated: 2008-05-19T10:03:00Z
-.. metalink::
-    :rel=self: http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/
+[[!meta title="Spec-writing On A Plane"]]
+[[!meta guid="http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/"]]
+[[!meta date="2008-05-19T10:03:00Z"]]
+[[!meta atom.entry.updated="2008-05-19T10:03:00Z"]]
+[[!meta permalink="http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/"]]
 
 .. class:: atom-body
 

Add content from previous version of website
diff --git a/2008/01/20/xrandr.rst b/2008/01/20/xrandr.rst
new file mode 100644
index 0000000..84fbb5b
--- /dev/null
+++ b/2008/01/20/xrandr.rst
@@ -0,0 +1,51 @@
+============================
+A magical xrandr incantation
+============================
+
+.. meta::
+    :dcterms.created: 2008-01-20
+    :dcterms.modified: 2008-01-20
+    :atom.entry.id: http://smcv.pseudorandom.co.uk/2007/01/20/xrandr/
+    :atom.entry.published: 2008-01-20T17:23:13Z
+    :atom.entry.updated: 2008-01-20T17:23:13Z
+    :flatland.sites: smcv.pseudorandom.co.uk
+    :flatland.location: /2008/01/20/xrandr/
+.. metalink::
+    :rel=self: http://smcv.pseudorandom.co.uk/2008/01/20/xrandr/
+
+.. class:: atom-body
+
+    Here's a handy incantation I use with the Intel X.org graphics driver
+    on my laptop.
+
+    Put this script somewhere convenient::
+
+        #!/bin/sh
+        if xrandr | grep '^VGA connected' >/dev/null
+        then
+            #echo "VGA connected"
+            xrandr --output VGA --above LVDS --auto
+            xrandr --output LVDS --auto
+        else
+            #echo "VGA not connected"
+            xrandr --auto
+        fi 2>&1 | logger -t xrandr-hotkey
+
+    and bind it to your "switch video mode" key, e.g. Fn+F7 on my Thinkpad
+    X60s. For instance, I run xbindkeys_, so I saved it as ``autoxrandr`` and
+    put this in ~/xbindkeysrc::
+
+        "exec /home/smcv/bin/autoxrandr"
+            XF86Display
+
+    Now if you press the "switch video mode" key with a monitor plugged in,
+    you'll get the external monitor appearing above the laptop panel (my
+    preferred configuration - I've balanced my monitor on an N800 box to get
+    the bottom of the screen level with the top of my laptop's screen).
+    If you press that key again after unplugging the VGA cable, the laptop
+    will turn off the VGA output and pull all the windows onto the built-in
+    screen.
+
+    .. _xbindkeys: http://packages.debian.org/xbindkeys
+..
+  vim: set sw=4 sts=4 et:
diff --git a/2008/04/01/codegen.rst b/2008/04/01/codegen.rst
new file mode 100644
index 0000000..47490f6
--- /dev/null
+++ b/2008/04/01/codegen.rst
@@ -0,0 +1,30 @@
+===================
+Here's how it works
+===================
+
+.. meta::
+    :dcterms.created: 2008-04-01
+    :dcterms.modified: 2008-04-01
+    :atom.entry.id: http://smcv.pseudorandom.co.uk/2008/04/01/codegen/
+    :atom.entry.published: 2008-04-01T18:21:06Z
+    :atom.entry.updated: 2008-04-01T18:21:06Z
+    :flatland.sites: smcv.pseudorandom.co.uk
+    :flatland.location: /2008/04/01/codegen/
+.. metalink::
+    :rel=self: http://smcv.pseudorandom.co.uk/2008/04/01/codegen/
+
+.. class:: atom-body
+
+    Daf_ recently described a large part of my job, in diagrammatic form:
+
+    .. image:: /2008/04/generation.png
+        :alt: The secret Collabora code-generation process
+        :width: 495
+        :height: 700
+
+    (`source`_)
+
+    .. _daf: http://dgh.livejournal.com/
+    .. _source: http://people.collabora.co.uk/~daf/
+..
+  vim: set sw=4 sts=4 et:
diff --git a/2008/04/18/dd.rst b/2008/04/18/dd.rst
new file mode 100644
index 0000000..1469dcb
--- /dev/null
+++ b/2008/04/18/dd.rst
@@ -0,0 +1,25 @@
+====
+\\o/
+====
+
+.. meta::
+    :dcterms.created: 2008-04-18
+    :dcterms.modified: 2008-04-18
+    :atom.entry.id: http://smcv.pseudorandom.co.uk/2008/04/18/dd/
+    :atom.entry.published: 2008-04-18T15:23:00Z
+    :atom.entry.updated: 2008-04-18T15:23:00Z
+.. metalink::
+    :rel=self: http://smcv.pseudorandom.co.uk/2008/04/18/dd/
+
+.. class:: atom-body
+
+ I'm now a full Debian developer! Slightly too late to vote for `my landlord`_
+ as project leader, but it's OK, he got in anyway :-)
+
+ Thanks to the NM team, the newly delegated keyring maintainer, and the
+ previous DPL's eleventh-hour redelegation for making this happen!
+
+.. _my landlord: http://blog.einval.com/
+
+..
+  vim: set sw=4 sts=4 et:
diff --git a/2008/05/16/onaplane.rst b/2008/05/16/onaplane.rst
new file mode 100644
index 0000000..bfe33d4
--- /dev/null
+++ b/2008/05/16/onaplane.rst
@@ -0,0 +1,114 @@
+=======================
+Spec-writing On A Plane
+=======================
+
+.. meta::
+    :dcterms.created: 2008-05-16
+    :dcterms.modified: 2008-05-19
+    :atom.entry.id: http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/
+    :atom.entry.published: 2008-05-19T10:03:00Z
+    :atom.entry.updated: 2008-05-19T10:03:00Z
+.. metalink::
+    :rel=self: http://smcv.pseudorandom.co.uk/2008/05/16/onaplane/
+
+.. class:: atom-body
+
+  (Written on Friday 16th, posted on Monday)
+
+  As I write this, I'm on a plane off the coast of the Netherlands, on the way
+  back from a couple of days designing APIs with `Rob McQueen`_ and the RTCom
+  people at NRC Helsinki (who we_ work with on the chat and VoIP functionality
+  for Nokia internet tablets).
+
+  We've had a very useful couple of days, mainly designing the next-generation
+  channel requesting and dispatch API for Telepathy_ (the same APIs I've been
+  doing preparatory work for on the Telepathy mailing list in the last couple of
+  weeks). API sketches for review and comment are either on are on
+  `Merge Monkey`_ or on the way there.
+
+  Before even reaching Nokia, Rob and I did a lot of design on the plane over to
+  Helsinki, and I took some notes: here they are, by way of a glimpse at how the
+  Telepathy design process works when we don't have a
+  whiteboard\ [#f20080516whiteboard]_ :-)
+
+    * Geoloc looks good in principle, needs some more work
+
+      - add more docstrings
+
+      - add a way to ask people for uncached info (RequestLocations)
+
+      - move access control to Co.I.Presence, call it RichPresenceAccessControl?
+
+    * DeliveryReporting looks good, ish
+
+      - improve wording of delivery-echo and rationale
+
+      - when sending a delivery report, add a reason for the status (using
+        Channel_Text_Send_Error?)
+
+    * Uniqueness requirement for (channel, handle_type != 0, handle) is in the
+      way - let's drop it
+
+    * MSN should use "authentic" 1-1 chats, and use Ch.I.UpgradeableToRoom
+      (name tbd) to migrate the underlying switchboard to be a room
+
+    * XMPP should use Ch.I.UpgradeableToRoom too, but the 1-1 channel may also
+      stay open
+
+    * Mutable handle => handle 0 must stay (for requestotron's benefit)
+
+    * bundles ftw
+
+    * renaming: we want SelfHandleChanged in the core
+
+    * TpC* - add ability to subscribe to ifaces ay construct time (blocks Ready)
+      or later
+
+    * Dispatching: when registering a c'handler, specify everything it can
+      handle
+
+    * If a new bundle can be handled in its entirety by the same handler

(Diff truncated)