Recent changes to this wiki:

update blogroll
diff --git a/blog.mdwn b/blog.mdwn
index 86c6f0b..ed4c232 100644
--- a/blog.mdwn
+++ b/blog.mdwn
@@ -26,9 +26,9 @@ Posts per month:
 
 My other blogs:
 
-* [git-annex dev blog](http://git-annex.branchable.com/design/assistant/blog)
+* [git-annex dev blog](https://git-annex.branchable.com/devblog/)
 * [olduse.net blog](http://olduse.net/blog/)
-* [after 1 minute on my modem](http://1-minute-modem.branchable.com)
+* [after 1 minute on my modem](https://1-minute-modem.branchable.com)
 
 Other feeds:
 

comment
diff --git a/blog/entry/dealing_with_dialup/comment_2_4bc8ba277f519f3d04da199bd0a97ecb._comment b/blog/entry/dealing_with_dialup/comment_2_4bc8ba277f519f3d04da199bd0a97ecb._comment
new file mode 100644
index 0000000..a37efeb
--- /dev/null
+++ b/blog/entry/dealing_with_dialup/comment_2_4bc8ba277f519f3d04da199bd0a97ecb._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2015-01-28T16:28:11Z"
+ content="""
+I made that blog post in 2007. What do you think?
+
+... Yeah, of course I'm back on dialup!
+
+See also: 
+
+* [[slow]] (why dialup helps you think)
+* [[roundtrip_latency_from_a_cabin_with_dialup_in_2011]]
+* [after 1 minute on my modem](http://1-minute-modem.branchable.com)
+
+If you feel stuck in a rut or unable to concentrate, go spend a week or a
+month in a cabin with dialup and git and a haskell compiler. It's worked
+great for me.
+"""]]

Added a comment: curious
diff --git a/blog/entry/dealing_with_dialup/comment_1_9a52e2f46fd64302f7ae46e7687e8fb9._comment b/blog/entry/dealing_with_dialup/comment_1_9a52e2f46fd64302f7ae46e7687e8fb9._comment
new file mode 100644
index 0000000..15c7238
--- /dev/null
+++ b/blog/entry/dealing_with_dialup/comment_1_9a52e2f46fd64302f7ae46e7687e8fb9._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="jmz"
+ subject="curious"
+ date="2015-01-28T07:21:20Z"
+ content="""
+Do you still use dial up? I've been meaning to learn a great deal of things but I'm horribly unproductive and find myself torrenting, watching videos, talks, podcasts, tutorials on youtube, etc but never really accomplishing much myself. I find it both amazing and inspiring that you accomplish so much and are so prolific on a dialup connection. Just curious if you've still stuck with dialup all these years later? I might be ditching expensive broadband in favor of something more frugal and trying to develop some self-discipline and a work ethic like yours. Thanks for all the work you've done on Debian and your other projects!
+"""]]

thread
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families/comment_1_c9c34bfe36d96691bd5a1c8da77aac5c._comment b/blog/entry/making_propellor_safer_with_GADTs_and_type_families/comment_1_c9c34bfe36d96691bd5a1c8da77aac5c._comment
new file mode 100644
index 0000000..7d5ffdd
--- /dev/null
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families/comment_1_c9c34bfe36d96691bd5a1c8da77aac5c._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2015-01-25T19:57:30Z"
+ content="""
+The reddit comment thread was very interesting:
+<http://www.reddit.com/r/haskell/comments/2tl8v1/making_propellor_safer_with_gadts_and_type/>
+"""]]

context link
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
index 0a61c53..5fedf87 100644
--- a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -1,4 +1,5 @@
-Since July, I have been aware of an ugly problem with propellor. Certain
+Since July, I have been aware of an ugly problem with 
+[propellor](https://propellor.branchable.com/). Certain
 propellor configurations could have a bug. I've tried to solve the problem at
 least a half-dozen times without success; it's eaten several weekends. 
 

Added a comment: Special remote for Dropbox
diff --git a/blog/entry/case_study:_adding_box.com_support_to_git-annex/comment_4_24d6e3cbc3075f3cd8dd96f2ce5df5b0._comment b/blog/entry/case_study:_adding_box.com_support_to_git-annex/comment_4_24d6e3cbc3075f3cd8dd96f2ce5df5b0._comment
new file mode 100644
index 0000000..ecc54eb
--- /dev/null
+++ b/blog/entry/case_study:_adding_box.com_support_to_git-annex/comment_4_24d6e3cbc3075f3cd8dd96f2ce5df5b0._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawmFiUAk6J121dyb5bzx2Ga6STjpn9YPHFk"
+ nickname="Salim"
+ subject="Special remote for Dropbox"
+ date="2015-01-25T13:23:53Z"
+ content="""
+Hi Joey
+A bit late the party, but I'm really enthused about what you've done with git-annex!
+
+I've migrated my main machine to use only open-source software, but am still locked into Dropbox because that's what everyone in my company uses. Since Dropbox insists on installing proprietary software in its client, that's a no-go for me. (My experiments with OwnCloud and a proxy machine runnnig OC and DB failed because Dropbox was too unreliable at handling conflicts, and OC was a CPU hog.)
+
+I bet you've seen https://github.com/TobiasTheViking/dropboxannex by now. (Surprised it wasn't listed in the walkthrough.) I'm about to give it a spin. 
+
+If you're request for a Dropbox account or sponsorship still stands, please let me know.  I think it'd be a great stepping stone for a lot of locked in Dropbox users to be able leave the Dark Side.
+"""]]

format
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
index e287ee7..0a61c53 100644
--- a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -95,7 +95,11 @@ Now I was able to write 4 instances of `Combines`, for each combination
 of 2 Properties with HasInfo or NoInfo.
 
 It type checked. But, type inference was busted. A simple expression
-like <pre>foo `requires` bar</pre> blew up:
+like 
+
+	foo `requires` bar
+
+blew up:
 
 	   No instance for (Requires (Property HasInfo) (Property HasInfo) r0)
 	      arising from a use of `requires'
@@ -106,7 +110,7 @@ like <pre>foo `requires` bar</pre> blew up:
 	                 (Property HasInfo) (Property HasInfo) (Property HasInfo)
 	        -- Defined at Propellor/Types.hs:167:10
 
-To avoid that, it needed <pre>(foo `requires` bar) :: Property HasInfo</pre> --
+To avoid that, it needed ":: Property HasInfo" appended --
 I didn't want the user to need to write that.
 
 I got stuck here for an long time, well over a month.

format
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
index 3268552..e287ee7 100644
--- a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -106,7 +106,7 @@ like <pre>foo `requires` bar</pre> blew up:
 	                 (Property HasInfo) (Property HasInfo) (Property HasInfo)
 	        -- Defined at Propellor/Types.hs:167:10
 
-To avoid that, it needed <pre(foo `requires` bar) :: Property HasInfo</pre> --
+To avoid that, it needed <pre>(foo `requires` bar) :: Property HasInfo</pre> --
 I didn't want the user to need to write that.
 
 I got stuck here for an long time, well over a month.

format
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
index 9addbf0..3268552 100644
--- a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -95,7 +95,7 @@ Now I was able to write 4 instances of `Combines`, for each combination
 of 2 Properties with HasInfo or NoInfo.
 
 It type checked. But, type inference was busted. A simple expression
-like <tt>foo `requires` bar</tt> blew up:
+like <pre>foo `requires` bar</pre> blew up:
 
 	   No instance for (Requires (Property HasInfo) (Property HasInfo) r0)
 	      arising from a use of `requires'
@@ -106,7 +106,7 @@ like <tt>foo `requires` bar</tt> blew up:
 	                 (Property HasInfo) (Property HasInfo) (Property HasInfo)
 	        -- Defined at Propellor/Types.hs:167:10
 
-To avoid that, it needed <tt>(foo `requires` bar) :: Property HasInfo</tt> --
+To avoid that, it needed <pre(foo `requires` bar) :: Property HasInfo</pre> --
 I didn't want the user to need to write that.
 
 I got stuck here for an long time, well over a month.

format
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
index 813d5b9..9addbf0 100644
--- a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -95,7 +95,7 @@ Now I was able to write 4 instances of `Combines`, for each combination
 of 2 Properties with HasInfo or NoInfo.
 
 It type checked. But, type inference was busted. A simple expression
-like `foo \`requires\` bar` blew up:
+like <tt>foo `requires` bar</tt> blew up:
 
 	   No instance for (Requires (Property HasInfo) (Property HasInfo) r0)
 	      arising from a use of `requires'
@@ -106,7 +106,7 @@ like `foo \`requires\` bar` blew up:
 	                 (Property HasInfo) (Property HasInfo) (Property HasInfo)
 	        -- Defined at Propellor/Types.hs:167:10
 
-To avoid that, it needed `(foo \`requires\` bar) :: Property HasInfo` --
+To avoid that, it needed <tt>(foo `requires` bar) :: Property HasInfo</tt> --
 I didn't want the user to need to write that.
 
 I got stuck here for an long time, well over a month.

format
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
index ad3ac24..813d5b9 100644
--- a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -95,7 +95,7 @@ Now I was able to write 4 instances of `Combines`, for each combination
 of 2 Properties with HasInfo or NoInfo.
 
 It type checked. But, type inference was busted. A simple expression
-like "foo `requires` bar" blew up:
+like `foo \`requires\` bar` blew up:
 
 	   No instance for (Requires (Property HasInfo) (Property HasInfo) r0)
 	      arising from a use of `requires'

format
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
index 46e59bc..ad3ac24 100644
--- a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -106,7 +106,7 @@ like "foo `requires` bar" blew up:
 	                 (Property HasInfo) (Property HasInfo) (Property HasInfo)
 	        -- Defined at Propellor/Types.hs:167:10
 
-To avoid that, it needed "(foo `requires` bar) :: Property HasInfo" --
+To avoid that, it needed `(foo \`requires\` bar) :: Property HasInfo` --
 I didn't want the user to need to write that.
 
 I got stuck here for an long time, well over a month.

blog update
diff --git a/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
new file mode 100644
index 0000000..46e59bc
--- /dev/null
+++ b/blog/entry/making_propellor_safer_with_GADTs_and_type_families.mdwn
@@ -0,0 +1,198 @@
+Since July, I have been aware of an ugly problem with propellor. Certain
+propellor configurations could have a bug. I've tried to solve the problem at
+least a half-dozen times without success; it's eaten several weekends. 
+
+Today I finally managed to fix propellor so it's impossible to write code that
+has the bug, bending the Haskell type checker to my will with the power of
+GADTs and type-level functions.
+
+## the bug
+
+Code with the bug looked innocuous enough. Something like this:
+
+[[!format haskell """
+foo :: Property
+foo = property "foo" $
+	unlessM (liftIO $ doesFileExist "/etc/foo") $ do
+		bar <- liftIO $ readFile "/etc/foo.template"
+		ensureProperty $ setupFoo bar
+"""]]
+
+The problem comes about because some properties in propellor have Info
+associated with them. This is used by propellor to introspect over the
+properties of a host, and do things like set up DNS, or decrypt
+private data used by the property.
+
+At the same time, it's useful to let a Property internally decide to
+run some other Property. In the example above, that's the `ensureProperty`
+line, and the `setupFoo` Property is run only sometimes, and is
+passed data that is read from the filesystem.
+
+This makes it very hard, indeed probably impossible for Propellor to
+look inside the monad, realize that `setupFoo` is being used, and add
+its Info to the host.
+
+Probably, `setupFoo` doesn't have Info associated with it -- most
+properties do not. But, it's hard to tell, when writing such a Property
+if it's safe to use ensureProperty. And worse, `setupFoo` could later
+be changed to have Info.
+
+Now, in most languages, once this problem was noticed, the solution would
+probably be to make `ensureProperty` notice when it's called on a Property
+that has Info, and print a warning message. That's Good Enough in a sense.
+
+But it also really stinks as a solution. It means that building propellor
+isn't good enough to know you have a working system; you have to let it
+run on each host, and watch out for warnings. Ugh, no!
+
+## the solution
+
+This screams for GADTs. (Well, it did once I learned how what GADTs are
+and what they can do.) 
+
+With GADTs, `Property NoInfo` and `Property HasInfo` can be separate data
+types. Most functions will work on either type (`Property i`) but
+`ensureProperty` can be limited to only accept a `Property NoInfo`.
+
+[[!format haskell """
+data Property i where
+	IProperty :: Desc -> ... -> Info -> Property HasInfo
+	SProperty :: Desc -> ... -> Property NoInfo
+
+data HasInfo
+data NoInfo
+
+ensureProperty :: Property NoInfo -> Propellor Result
+"""]]
+
+Then the type checker can detect the bug, and refuse to compile it.
+
+Yay!
+
+Except ...
+
+## Property combinators
+
+There are a lot of Property combinators in propellor. These combine
+two or more properties in various ways. The most basic one is `requires`,
+which only runs the first Property after the second one has successfully
+been met.
+
+So, what's it's type when used with GADT Property?
+
+[[!format haskell """
+requires :: Property i1 -> Property i2 -> Property ???
+"""]]
+
+It seemed I needed some kind of type class, to vary the return type.
+
+[[!format haskell """
+class Combine x y r where
+	requires :: x -> y -> r
+"""]]
+
+Now I was able to write 4 instances of `Combines`, for each combination
+of 2 Properties with HasInfo or NoInfo.
+
+It type checked. But, type inference was busted. A simple expression
+like "foo `requires` bar" blew up:
+
+	   No instance for (Requires (Property HasInfo) (Property HasInfo) r0)
+	      arising from a use of `requires'
+	    The type variable `r0' is ambiguous
+	    Possible fix: add a type signature that fixes these type variable(s)
+	    Note: there is a potential instance available:
+	      instance Requires
+	                 (Property HasInfo) (Property HasInfo) (Property HasInfo)
+	        -- Defined at Propellor/Types.hs:167:10
+
+To avoid that, it needed "(foo `requires` bar) :: Property HasInfo" --
+I didn't want the user to need to write that.
+
+I got stuck here for an long time, well over a month.
+
+## type level programming
+
+Finally today I realized that I could fix this with a little type-level
+programming.
+
+[[!format haskell """
+class Combine x y where
+	requires :: x -> y -> CombinedType x y
+"""]]
+
+Here `CombinedType` is a type-level function, that calculates the type that
+should be used for a combination of types x and y. This turns out to be really
+easy to do, once you get your head around type level functions.
+
+[[!format haskell """
+type family CInfo x y
+type instance CInfo HasInfo HasInfo = HasInfo
+type instance CInfo HasInfo NoInfo = HasInfo
+type instance CInfo NoInfo HasInfo = HasInfo
+type instance CInfo NoInfo NoInfo = NoInfo
+type family CombinedType x y
+type instance CombinedType (Property x) (Property y) = Property (CInfo x y)
+"""]]
+
+And, with that change, type inference worked again! \o/
+
+(Bonus: I added some more intances of CombinedType for combining
+things like RevertableProperties, so propellor's property
+combinators got more powerful too.)
+
+Then I just had to make a massive pass over all of Propellor,
+fixing the types of each Property to be Property NoInfo or Property HasInfo.
+I frequently picked the wrong one, but the type checker was able to detect 
+and tell me when I did.
+
+A few of the type signatures got slightly complicated, to provide the type
+checker with sufficient proof to do its thing...
+
+[[!format haskell """
+before :: (IsProp x, Combines y x, IsProp (CombinedType y x)) => x -> y -> CombinedType y x
+before x y = (y `requires` x) `describe` (propertyDesc x)
+
+onChange
+	:: (Combines (Property x) (Property y))
+	=> Property x
+	=> Property y
+	=> CombinedType (Property x) (Property y)
+onChange = -- 6 lines of code omitted
+
+fallback :: (Combines (Property p1) (Property p2)) => Property p1 -> Property p2 -> Property (CInfo p1 p2)
+fallback = -- 4 lines of code omitted
+"""]]
+
+.. This mostly happened in property combinators, which is an acceptable
+tradeoff, when you consider that the type checker is now being used to prove
+that propellor can't have this bug.
+
+Mostly, things went just fine. The only other annoying thing was that some
+things use a `[Property]`, and since a haskell list can only contain a
+single type, while Property Info and Property NoInfo are two different
+types, that needed to be dealt with. Happily, I was able to extend
+propellor's existing `(&)` and `(!)` operators to work in this situation,
+so a list can be constructed of properties of several different types:
+
+[[!format haskell """
+propertyList "foos" $ props
+	& foo
+	& foobar
+	! oldfoo	
+"""]]
+
+## conclusion
+
+The resulting 4000 lines of changes will be in the next release of
+propellor. Just as soon as I test that it always generates the same Info
+as before, and perhaps works when I run it. (eep)
+
+These uses of GADTs and type families are not new; this is merely the first
+time I used them. It's another Haskell leveling up for me. 
+
+Anytime you can identify a class of bugs that can impact a complicated code

(Diff truncated)
add news item for moreutils 0.55
diff --git a/code/moreutils/news/version_0.49.mdwn b/code/moreutils/news/version_0.49.mdwn
deleted file mode 100644
index e507d68..0000000
--- a/code/moreutils/news/version_0.49.mdwn
+++ /dev/null
@@ -1,6 +0,0 @@
-moreutils 0.49 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * ts: Fix timezone used with -i
-   * errno, isutf8: Fix zero-termination of option list, which could lead
-     to getopt crash. Closes: #[715867](http://bugs.debian.org/715867)
-     (Thanks, Mayhem Team)"""]]
\ No newline at end of file
diff --git a/code/moreutils/news/version_0.55.mdwn b/code/moreutils/news/version_0.55.mdwn
new file mode 100644
index 0000000..dfe7d60
--- /dev/null
+++ b/code/moreutils/news/version_0.55.mdwn
@@ -0,0 +1,6 @@
+moreutils 0.55 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * parallel: serialise output through internal pipe. Closes: #[704125](http://bugs.debian.org/704125)
+     Thanks, Nicolas Schier.
+   * sponge: add append option '-a'. Closes: #[623197](http://bugs.debian.org/623197)
+     Thanks, Nicolas Schier."""]]
\ No newline at end of file

correction
diff --git a/code/bin.mdwn b/code/bin.mdwn
index 31b7669..a4ff3e5 100644
--- a/code/bin.mdwn
+++ b/code/bin.mdwn
@@ -42,7 +42,7 @@ This is the script that I use for releasing packages.
 ## wikiannounce
 
 This is a script that release calls, which converts a changelog into
-a news item for a package on this wiki.
+a news item for a package on its wiki.
 
 ## foto
 

more
diff --git a/code/bin.mdwn b/code/bin.mdwn
index cdd6dab..31b7669 100644
--- a/code/bin.mdwn
+++ b/code/bin.mdwn
@@ -12,6 +12,12 @@ there still.
 
 You can browse my bin at <http://git.kitenet.net/?p=joey/home.git;a=tree;f=bin>.
 
+## async
+
+Passed a mount point and a command, it remounts the drive at that point
+async, runs the command, and then remounts it back sync. Useful with
+external drives that are mounted sync by default for safety.
+
 ## blog
 
 This brings up a text editor for writing a
@@ -38,12 +44,10 @@ This is the script that I use for releasing packages.
 This is a script that release calls, which converts a changelog into
 a news item for a package on this wiki.
 
-## dq
-
-This is my Download Queue program. Uses rsync to synchronise files, very
-handy if you're on a slow modem link.
+## foto
 
-(Now obsoleted by [[code/git-annex]])
+Pulls photos off a camera. Either from a DCIM directory of a mounted SD
+card, or using gphoto2 over USB. The photos are added to a git-annex repo.
 
 ## loadcron
 
@@ -55,6 +59,11 @@ Supports some handy features.
 Given a list of architectures on command line or stdin, 
 outputs any of the released debian arches not in the list
 
+## lifeday
+
+Prints out the number of days since I was born. Useful for a different
+perspective.
+
 ## logview
 
 What I use for tailing logfiles. Determines dynamically what files are
@@ -67,11 +76,20 @@ which sucks on 3 line xterms).
 Sshs into a machine and starts a screen session. Auto-reconnects.
 Goto considered wonderful!
 
-## scancd
+## out
 
-I keep a file that records all the files on archival CDs that I burn; this
-updates the file. Uses vim folding markers to make it easy to browse the
-file in vim; the file is also always stored compressed. (It's big.)
+For use in a git-annex repository containing files that are being consumed
+in some way (eg, videos or podcasts), where I want to keep a copy of the
+file but get it out of the way when done with it. Moves specified files to
+some "out" directory located inside the repository, and has git-annex drop
+their content if possible.
+
+## rec
+
+Simple sound recorder. Streams the mic to a fifo and in the background,
+encodes it to an ogg file. This can be easily started up, and runs until
+ctrl-C'd. Then the finished ogg file is stashed away in a git-annex
+repository.
 
 ## sunrise
 
@@ -85,3 +103,10 @@ It does have to have LAT/LONG hardcoded into it though.
 This makes su actually run the the sudo command, if sudo is present. Nice
 to not have to type the password every time when suing, although I wrote it
 before I was aware of "`sudo su`".
+
+## z
+
+Blocks suspend on lid close while a command runs. Useful for eg, listening
+to a podcast, or keeping the laptop running until a download completes.
+
+Requires some systemd setup documented in comments.

update
diff --git a/code/bin.mdwn b/code/bin.mdwn
index ab0f31f..cdd6dab 100644
--- a/code/bin.mdwn
+++ b/code/bin.mdwn
@@ -22,20 +22,20 @@ with pyblosxom instead.
 
 ## build
 
-This is the script that I use for building Debian packages.
+This is the script that I use for building packages.
 
 ## review
 
-This is the script I use for running lintian and other checks on a Debian
+This is the script I use for running lintian and other checks on a
 package I've built. It displays all sorts of useful info in a pager.
 
 ## release
 
-This is the script that I use for releasing Debian packages.
+This is the script that I use for releasing packages.
 
 ## wikiannounce
 
-This is a script that release calls, which converts a debian changelog into
+This is a script that release calls, which converts a changelog into
 a news item for a package on this wiki.
 
 ## dq

reorg
diff --git a/code.mdwn b/code.mdwn
index 1701230..a624f5c 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -28,35 +28,42 @@ In maintenance mode mostly, but I still have my hands in it somewhat.
 
 ## Past projects
 
-I'm no longer working on these projects.
+I'm no longer working on these projects, but thankfully, other
+people have taken them on.
 
 [[Debian]]
 [[debian-installer]]
 [[debhelper]]
 [[tasksel]]
-[[debmirror]]
-[[shoop]]
-[[apt-src]]
-[[pentium-builder]]
-[[perlmoo]]
-[[TermStool]]
-[[base-config]]
 [[flashybrid]]
-[[satutils]]
-[[mooix]]
 [[wmbattery]]
-[[sleepd]]
-[[pristine-tar]]
-[[alien]]
 [[debconf]]
 [[dpkg-repack]]
 [[os-prober]]
 [[devscripts]]
+[[pentium-builder]]
+[[apt-src]]
+
+These need new maintainers, stat!
+
+[[debmirror]]
+[[sleepd]]
+[[pristine-tar]]
+[[alien]]
 [[jetring]]
 [[nslu2-utils]]
-[[rootsync]]
 [[ticker]]
 
+These are dead and buried.
+
+[[shoop]]
+[[perlmoo]]
+[[TermStool]]
+[[base-config]]
+[[satutils]]
+[[mooix]]
+[[rootsync]]
+
 ## Misc
 
 Other stuff..
diff --git a/code/debian-installer.mdwn b/code/debian-installer.mdwn
index 5573352..dcf0905 100644
--- a/code/debian-installer.mdwn
+++ b/code/debian-installer.mdwn
@@ -8,5 +8,5 @@ Its website is formally <http://www.debian.org/devel/debian-installer>, but
 <http://wiki.debian.org/DebianInstaller> is perhaps more interesting.
 
 The [[dilab]] was my own rack of d-i test
-machines. This runs on `digress`, the d-i regression suite, which is the
+machines. This ran on `digress`, the d-i regression suite, which is the
 most obscure part of d-i I know of, and which I wrote.

update re oprhanings and etc
diff --git a/code.mdwn b/code.mdwn
index a331b58..1701230 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -28,12 +28,7 @@ In maintenance mode mostly, but I still have my hands in it somewhat.
 
 ## Past projects
 
-Still theoretically maintained by me, but new maintainers needed for
-continued life:
-
-[[ticker]]
-
-Passed on to others, or dead and buried:
+I'm no longer working on these projects.
 
 [[Debian]]
 [[debian-installer]]
@@ -60,6 +55,7 @@ Passed on to others, or dead and buried:
 [[jetring]]
 [[nslu2-utils]]
 [[rootsync]]
+[[ticker]]
 
 ## Misc
 
diff --git a/code/debhelper.mdwn b/code/debhelper.mdwn
index 75feb55..b0dabf3 100644
--- a/code/debhelper.mdwn
+++ b/code/debhelper.mdwn
@@ -29,9 +29,7 @@ maintaining support for said obscure thing.
 
 My first rule of thumb is that at least ten packages need to be obvious
 benefactors of a feature or command before it's added to debhelper. That's
-an easy bar; after that I have to do some thinking and made the hard call.
-
-TODO: discuss wishlisted commands here
+an easy bar; after that I have to do some thinking and make the hard call.
 
 [[!sidebar content="""
 <a href="http://flattr.com/thing/39941/Debhelper" target="_blank">
diff --git a/code/debhelper/news/no_longer_maintaining_debhelper.mdwn b/code/debhelper/news/no_longer_maintaining_debhelper.mdwn
new file mode 100644
index 0000000..46ba21b
--- /dev/null
+++ b/code/debhelper/news/no_longer_maintaining_debhelper.mdwn
@@ -0,0 +1,2 @@
+I've passed maintanence for debhelper on to others. This page is provided
+only for historical reasons.

orphaned ailen
diff --git a/code/alien/news/no_longer_maintaining_alien.mdwn b/code/alien/news/no_longer_maintaining_alien.mdwn
new file mode 100644
index 0000000..692aa0d
--- /dev/null
+++ b/code/alien/news/no_longer_maintaining_alien.mdwn
@@ -0,0 +1 @@
+I am no longer maintaining alien. A new maintainer is wanted.

mooix archive link etc
diff --git a/code/mooix.mdwn b/code/mooix.mdwn
index ede096d..1375e85 100644
--- a/code/mooix.mdwn
+++ b/code/mooix.mdwn
@@ -1,9 +1,13 @@
 Mooix is a MOO that is implemented on top of unix and which can be
-programmed online in any language. Its website is <http://mooix.net/>.
+programmed online in any language.
 
-I'm not currently using or developing mooix; a few other people make
-commits from time to time. I have some [[grandiose_plans|ng]] for the next
-generation of mooix, which I might get around to fleshing out some day.
+I stopped developing mooix around 2001; a few other people made
+commits from time to time for the next decade, but now it is done.
+
+I have some [[grandiose_plans|ng]] for the next generation of mooix,
+which I might get around to fleshing out some day, but probably not.
 
 Some thoughts on mooix in my
 [[blog|blog/entry/ten_years_of_free_software_--_part_17_mooix]].
+
+Mooix is archived: <https://archive.org/details/MooixArchive>

Added a comment: bug in my ear
diff --git a/blog/entry/a_bug_in_my_ear/comment_7_a4ea38bfa03050cfb39bb084a247eb85._comment b/blog/entry/a_bug_in_my_ear/comment_7_a4ea38bfa03050cfb39bb084a247eb85._comment
new file mode 100644
index 0000000..860ae44
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_7_a4ea38bfa03050cfb39bb084a247eb85._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawkjqspuRFhqOXA8hoESjDm0I45gYL9v9Lk"
+ nickname="Peter"
+ subject="bug in my ear"
+ date="2015-01-06T10:31:28Z"
+ content="""
+Never EVER use a cotton bud!
+1. Your parents probably taught you that and it's really bad.
+2. Cotton buds generally fill the ear canal and then like loading a cannon (That's apt?) push all that crap further down your ear like a ram rod.
+
+Some people use hair grips a bit like a scraper but you need to be dead careful not to damage the ear drum. Best option warm olive oil and pour that in your lughole (Urban Dictionary) after a couple of minutes drain it out. The warmer the better to melt any minging ear wax. :-)
+"""]]

Added a comment: RC?
diff --git a/blog/entry/a_bug_in_my_ear/comment_6_2c4011193d9dd2497ba6aea159bb237c._comment b/blog/entry/a_bug_in_my_ear/comment_6_2c4011193d9dd2497ba6aea159bb237c._comment
new file mode 100644
index 0000000..2d70802
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_6_2c4011193d9dd2497ba6aea159bb237c._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="http://www.joachim-breitner.de/"
+ nickname="nomeata"
+ subject="RC?"
+ date="2015-01-06T10:00:52Z"
+ content="""
+So you are saying that while this bug was not critical for the release, the release of this bug was critical for you?
+"""]]

tag
diff --git a/blog/entry/hledger.mdwn b/blog/entry/hledger.mdwn
index 85d8ae3..324f48c 100644
--- a/blog/entry/hledger.mdwn
+++ b/blog/entry/hledger.mdwn
@@ -221,3 +221,5 @@ Of course, a Haskell programmer can skip the monads entirely, or use others
 they prefer. And could do arbitrarily complicated stuff during imports,
 including building split transactions, and combining together multiple
 related CVS lines into a single transaction.
+
+[[!tag haskell]]

foo
diff --git a/blog/entry/a_bug_in_my_ear/comment_5_e62e8977fc1f67c4d44654b483c30adb._comment b/blog/entry/a_bug_in_my_ear/comment_5_e62e8977fc1f67c4d44654b483c30adb._comment
new file mode 100644
index 0000000..66de52e
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_5_e62e8977fc1f67c4d44654b483c30adb._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2015-01-06T05:29:38Z"
+ content="""
+I loled at the bug report comment!
+
+JFTR, the cue-tips I used are the big-ended safe kind that intentionally cannot
+be jammed all the way down the canal to the eardrum.
+
+A few years ago, I had a strange earache, that came on without any swimming
+or other activity that might lead to an ear infection. Now I'm wondering if
+that one was also caused by some little bug, perhaps while I was asleep.
+
+Ear canals.. what was evolution thinking?
+"""]]

Added a comment
diff --git a/blog/entry/a_bug_in_my_ear/comment_4_b7d72d7147ddb255492007389e09f1da._comment b/blog/entry/a_bug_in_my_ear/comment_4_b7d72d7147ddb255492007389e09f1da._comment
new file mode 100644
index 0000000..80af23a
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_4_b7d72d7147ddb255492007389e09f1da._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawndhZ128v4P20FCgptVRqrP0bOwPpi2EQA"
+ nickname="Patrick"
+ subject="comment 4"
+ date="2015-01-06T03:20:08Z"
+ content="""
+Happened to me when I was around 10 years old.  I remember thinking it was going to flap in there forever.
+"""]]

Added a comment
diff --git a/blog/entry/a_bug_in_my_ear/comment_3_fa24ff02463a7396ef768cdff7e5d04c._comment b/blog/entry/a_bug_in_my_ear/comment_3_fa24ff02463a7396ef768cdff7e5d04c._comment
new file mode 100644
index 0000000..e7d9dd6
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_3_fa24ff02463a7396ef768cdff7e5d04c._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawlYPDgJVIC9eiG2E7I480vFHmmWXn0Nauc"
+ nickname="Piruthiviraj"
+ subject="comment 3"
+ date="2015-01-06T03:05:15Z"
+ content="""
+People, never try earbuds to remove the living foreign body from the ear. First stop panicking! Rest the head on a bed and always use fluids eg. lukewarm water to fill the ear canal and usually after few mins, bugs usually comes out or at least dies and helps in easier extraction at the hospital.
+If you have been diagnosed to have previous ear infection or a persistant ear perforation, always seek medical help, before manipulating yourself.
+The more the manipulation the more likely the bug or the earbud is going to injure the cavity and later leading a ear infection.
+I am an ER Physcian and hence you can depend on the info.
+"""]]

Added a comment
diff --git a/blog/entry/a_bug_in_my_ear/comment_2_0f4d749540e955b707a07f57284db9ca._comment b/blog/entry/a_bug_in_my_ear/comment_2_0f4d749540e955b707a07f57284db9ca._comment
new file mode 100644
index 0000000..44039f1
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_2_0f4d749540e955b707a07f57284db9ca._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawn8AYPzWP-WL-z-EOr_EBp7Kd44DxEYNxE"
+ nickname="Benjamin"
+ subject="comment 2"
+ date="2015-01-06T02:23:54Z"
+ content="""
+The exact same thing happened to my girlfriend about 10 years ago. She treated it with ear-drops just like you did, and she doesn't suffer any drawback except from being afraid by those kind of bugs. So my guess is that you should be alright too :-)
+"""]]

removed
diff --git a/blog/entry/a_bug_in_my_ear/comment_2_5872742ed8e7cce48993cbbfb923d7f4._comment b/blog/entry/a_bug_in_my_ear/comment_2_5872742ed8e7cce48993cbbfb923d7f4._comment
deleted file mode 100644
index ca03ca7..0000000
--- a/blog/entry/a_bug_in_my_ear/comment_2_5872742ed8e7cce48993cbbfb923d7f4._comment
+++ /dev/null
@@ -1,7 +0,0 @@
-[[!comment format=mdwn
- username="http://bret.io/"
- subject="comment 2"
- date="2015-01-06T01:58:58Z"
- content="""
-Thanks for your bug report.  ;)
-"""]]

Added a comment
diff --git a/blog/entry/a_bug_in_my_ear/comment_2_5872742ed8e7cce48993cbbfb923d7f4._comment b/blog/entry/a_bug_in_my_ear/comment_2_5872742ed8e7cce48993cbbfb923d7f4._comment
new file mode 100644
index 0000000..ca03ca7
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_2_5872742ed8e7cce48993cbbfb923d7f4._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="http://bret.io/"
+ subject="comment 2"
+ date="2015-01-06T01:58:58Z"
+ content="""
+Thanks for your bug report.  ;)
+"""]]

Added a comment
diff --git a/blog/entry/a_bug_in_my_ear/comment_1_51853f770fe2e217878b582dbab3e701._comment b/blog/entry/a_bug_in_my_ear/comment_1_51853f770fe2e217878b582dbab3e701._comment
new file mode 100644
index 0000000..d205f08
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear/comment_1_51853f770fe2e217878b582dbab3e701._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="http://bret.io/"
+ subject="comment 1"
+ date="2015-01-06T01:58:50Z"
+ content="""
+Thanks for your bug report.  ;)
+"""]]

blog update
diff --git a/blog/entry/a_bug_in_my_ear.mdwn b/blog/entry/a_bug_in_my_ear.mdwn
new file mode 100644
index 0000000..1b6e171
--- /dev/null
+++ b/blog/entry/a_bug_in_my_ear.mdwn
@@ -0,0 +1,18 @@
+True story: Two days ago, as I was about to drift off to sleep at 2 am, a tiny
+little bug flew into my ear. Right down to my eardrum, which it fluttered
+against with its wings.
+
+It was a tiny little moth-like bug, the kind you don't want to find in a bag of
+flour, and it had been beating against my laptop screen a few minutes before.
+
+This went on for 20 minutes, in which I failed to get it out with a cue tip and
+shaking my head. It is very weird to have a bug flapping in your head.
+
+I finally gave up and put in eardrops, and stopped the poor thing flapping. I
+happen to know these little creatures mass almost nothing, and rapidly break up
+into nearly powder when dead. So while I've not had any bug bits come out, I'm
+going by the way my ear felt a little stopped up yesterday, and just fine
+today, and guessing it'll be ok. Oh, and I've been soaking it in the tub and
+putting in eardrops for good measure.
+
+If I've seemed a little distracted lately, now you know why!

calendar update
diff --git a/blog/archives/2015.mdwn b/blog/archives/2015.mdwn
new file mode 100644
index 0000000..801aa04
--- /dev/null
+++ b/blog/archives/2015.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2015 pages="blog/entry/* and !*/Discussion"]]
diff --git a/blog/archives/2015/01.mdwn b/blog/archives/2015/01.mdwn
new file mode 100644
index 0000000..55e62f8
--- /dev/null
+++ b/blog/archives/2015/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/02.mdwn b/blog/archives/2015/02.mdwn
new file mode 100644
index 0000000..47ca1c8
--- /dev/null
+++ b/blog/archives/2015/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/03.mdwn b/blog/archives/2015/03.mdwn
new file mode 100644
index 0000000..6e9a783
--- /dev/null
+++ b/blog/archives/2015/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/04.mdwn b/blog/archives/2015/04.mdwn
new file mode 100644
index 0000000..05a8508
--- /dev/null
+++ b/blog/archives/2015/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/05.mdwn b/blog/archives/2015/05.mdwn
new file mode 100644
index 0000000..775c0e1
--- /dev/null
+++ b/blog/archives/2015/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/06.mdwn b/blog/archives/2015/06.mdwn
new file mode 100644
index 0000000..5bea3ab
--- /dev/null
+++ b/blog/archives/2015/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/07.mdwn b/blog/archives/2015/07.mdwn
new file mode 100644
index 0000000..6e1a33f
--- /dev/null
+++ b/blog/archives/2015/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/08.mdwn b/blog/archives/2015/08.mdwn
new file mode 100644
index 0000000..cfafb75
--- /dev/null
+++ b/blog/archives/2015/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/09.mdwn b/blog/archives/2015/09.mdwn
new file mode 100644
index 0000000..68e4d24
--- /dev/null
+++ b/blog/archives/2015/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/10.mdwn b/blog/archives/2015/10.mdwn
new file mode 100644
index 0000000..01c1f46
--- /dev/null
+++ b/blog/archives/2015/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/11.mdwn b/blog/archives/2015/11.mdwn
new file mode 100644
index 0000000..3f5f6e2
--- /dev/null
+++ b/blog/archives/2015/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/blog/archives/2015/12.mdwn b/blog/archives/2015/12.mdwn
new file mode 100644
index 0000000..6ca3ef0
--- /dev/null
+++ b/blog/archives/2015/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2015 pages="blog/entry/* and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2015) and blog/entry/* and !*/Discussion" show=0 feeds=no reverse=yes]]

update with gpg key
not currently using jabber
diff --git a/contact.mdwn b/contact.mdwn
index 79d9fee..1d7d141 100644
--- a/contact.mdwn
+++ b/contact.mdwn
@@ -1,4 +1,4 @@
-* email: <id@joeyh.name> or <joey@kitenet.net> or <joeyh@debian.org>
-* jabber: [joey@kitenet.net](xmpp:joey@kitenet.net)
+* email: <id@joeyh.name>
+* gpg key: [E85A 5F63 B31D 24C1 EBF0  D81C C910 D922 2512 E3C7](http://pgp.cs.uu.nl/stats/2512E3C7.html)
 * identi.ca: <http://identi.ca/joeyh>
 * some ways to send me a "thank you" for my work, if you're so inclined: [[thanks]]

cia is missed
diff --git a/code.mdwn b/code.mdwn
index ccdab05..a331b58 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -72,7 +72,7 @@ Other stuff..
 [[sigprogs]]
 
 If you want to keep up with new projects, [[WhatsNew]] is a feed of any new
-pages I add to this site, and [[grep]] aggregates my recent commits.
+pages I add to this site.
 
 Also, [Ohloh](http://www.ohloh.net/accounts/6835) tracks and mines my commits to many projects 
 for interesting metrics.

update
diff --git a/code/sleepd.mdwn b/code/sleepd.mdwn
index 7faeae8..e9d9bb3 100644
--- a/code/sleepd.mdwn
+++ b/code/sleepd.mdwn
@@ -7,6 +7,8 @@ must be used to actually put the system to sleep.
 There is a Debian `sleepd` package, or you can download it from git
 (`git://git.kitenet.net/sleepd`).
 
+I am not longer maintaining sleepd.
+
 ## News
 
 [[!inline pages="code/sleepd/news/* and !*/Discussion" show="3"]]

add shell-monad page
diff --git a/blog/entry/shell_monad.mdwn b/blog/entry/shell_monad.mdwn
index 1f4d5d7..7ccf112 100644
--- a/blog/entry/shell_monad.mdwn
+++ b/blog/entry/shell_monad.mdwn
@@ -75,3 +75,5 @@ There's a lot of things that could be added to this library
 (`if`, `while`, redirection, etc), but I can already see using
 it in various parts of propellor and git-annex that need to generate
 shell code.
+
+[[!tag code/shell-monad]]
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index b1e1ec1..2fde83b 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -229,3 +229,4 @@ all 99 lines of it.
 	set -p; _handler () { :; 	_v=; 	read _v; 	case "${_v%%\ *}" in FOO) :; 		echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2; 	: ;; BAR) :; 		echo 'yay, I got a Bar' >&2; 	: ;; BAZ) :; 		for _x in $(seq 1 "${_v#[!\ ]*[\ ]}"); 		do :; 			echo 'yay, I got a Baz' "$_x" >&2; 		done; 	: ;; *) :; 		echo 'unknown protocol command' "${_v%%\ *}" >&2; 		false; 	: ;; esac; }; echo 'FOO starting up'; _handler; echo 'BAR '; _handler
 
 [[!tag haskell]]
+[[!tag code/shell-monad]]
diff --git a/code.mdwn b/code.mdwn
index bd7835a..ccdab05 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -13,6 +13,7 @@ The stuff that's swapped into my local cache at the moment.
 [[moreutils]]
 [[ikiwiki-hosting]]
 [[github-backup]]
+[[shell-monad]]
 
 ## Less active projects
 
@@ -23,7 +24,6 @@ In maintenance mode mostly, but I still have my hands in it somewhat.
 [[pdmenu]]
 [[filters]]
 [electrum-mnemonic](http://hackage.haskell.org/package/electrum-mnemonic)
-[shell-monad](http://hackage.haskell.org/package/shell-monad)
 [brainfuck-monad](http://hackage.haskell.org/package/brainfuck-monad)
 
 ## Past projects
diff --git a/code/shell-monad.mdwn b/code/shell-monad.mdwn
new file mode 100644
index 0000000..2c89bf5
--- /dev/null
+++ b/code/shell-monad.mdwn
@@ -0,0 +1,3 @@
+Haskell DSL that generates shell scripts.
+
+[shell-monad](http://hackage.haskell.org/package/shell-monad)

tagfix
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index f6aebc4..b1e1ec1 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -228,4 +228,4 @@ all 99 lines of it.
 	
 	set -p; _handler () { :; 	_v=; 	read _v; 	case "${_v%%\ *}" in FOO) :; 		echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2; 	: ;; BAR) :; 		echo 'yay, I got a Bar' >&2; 	: ;; BAZ) :; 		for _x in $(seq 1 "${_v#[!\ ]*[\ ]}"); 		do :; 			echo 'yay, I got a Baz' "$_x" >&2; 		done; 	: ;; *) :; 		echo 'unknown protocol command' "${_v%%\ *}" >&2; 		false; 	: ;; esac; }; echo 'FOO starting up'; _handler; echo 'BAR '; _handler
 
-[[!meta tag=haskell]]
+[[!tag haskell]]

re-rendered code after a bug fix
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index e0f2a64..f6aebc4 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -207,17 +207,17 @@ all 99 lines of it.
 		read _v
 		case "${_v%%\ *}" in FOO) :
 			echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2
-		;; BAR) :
+		: ;; BAR) :
 			echo 'yay, I got a Bar' >&2
-		;; BAZ) :
+		: ;; BAZ) :
 			for _x in $(seq 1 "${_v#[!\ ]*[\ ]}")
 			do :
 				echo 'yay, I got a Baz' "$_x" >&2
 			done
-		;; *) :
+		: ;; *) :
 			echo 'unknown protocol command' "${_v%%\ *}" >&2
 			false
-		;; esac
+		: ;; esac
 	}
 	echo 'FOO starting up'
 	_handler
@@ -226,6 +226,6 @@ all 99 lines of it.
 	
 ## the one-liner shell program
 	
-	set -p; _handler () { :; 	_v=; 	read _v; 	case "${_v%%\ *}" in FOO) :; 		echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2; 	;; BAR) :; 		echo 'yay, I got a Bar' >&2; 	;; BAZ) :; 		for _x in $(seq 1 "${_v#[!\ ]*[\ ]}"); 		do :; 			echo 'yay, I got a Baz' "$_x" >&2; 		done; 	;; *) :; 		echo 'unknown protocol command' "${_v%%\ *}" >&2; 		false; 	;; esac; }; echo 'FOO starting up'; _handler; echo 'BAR '; _handler
+	set -p; _handler () { :; 	_v=; 	read _v; 	case "${_v%%\ *}" in FOO) :; 		echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2; 	: ;; BAR) :; 		echo 'yay, I got a Bar' >&2; 	: ;; BAZ) :; 		for _x in $(seq 1 "${_v#[!\ ]*[\ ]}"); 		do :; 			echo 'yay, I got a Baz' "$_x" >&2; 		done; 	: ;; *) :; 		echo 'unknown protocol command' "${_v%%\ *}" >&2; 		false; 	: ;; esac; }; echo 'FOO starting up'; _handler; echo 'BAR '; _handler
 
 [[!meta tag=haskell]]

tag
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index 9ae14d3..e0f2a64 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -227,3 +227,5 @@ all 99 lines of it.
 ## the one-liner shell program
 	
 	set -p; _handler () { :; 	_v=; 	read _v; 	case "${_v%%\ *}" in FOO) :; 		echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2; 	;; BAR) :; 		echo 'yay, I got a Bar' >&2; 	;; BAZ) :; 		for _x in $(seq 1 "${_v#[!\ ]*[\ ]}"); 		do :; 			echo 'yay, I got a Baz' "$_x" >&2; 		done; 	;; *) :; 		echo 'unknown protocol command' "${_v%%\ *}" >&2; 		false; 	;; esac; }; echo 'FOO starting up'; _handler; echo 'BAR '; _handler
+
+[[!meta tag=haskell]]

link
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index f0f687f..9ae14d3 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -193,6 +193,11 @@ javascript.
 I'm getting the feeling that I won't be writing too many nontrivial shell
 scripts by hand anymore! :)
 
+## the complete haskell program
+
+[Is here](http://git.joeyh.name/?p=shell-monad.git;a=blob;f=examples/protocol.hs;h=23a7c83d777b0c69e1a3f9ee6079f394d89cc561;hb=925b5fefe0a4c7b8e1fa5b56b90b26317adafebd),
+all 99 lines of it.
+
 ## the pretty-printed shell program
 
 	#!/bin/sh

foo
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index a7f1830..f0f687f 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -76,9 +76,10 @@ speaks the protocol in arbitrary ways. For example:
 		resp <- protoExchangeIO (Foo "starting up")
 		-- etc
 
-But that's trivial and uninteresting. The interesting part is making the
-shell program speak the protocol, including doing various things when it
-receives the commands.
+But that's trivial and uninteresting. Anyone who has read to here certianly
+knows how to write haskell code in the IO monad. The interesting part is
+making the shell program speak the protocol, including doing various things
+when it receives the commands.
 
 	foo :: Script ()
 	foo = do

foo
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index ab72b3a..a7f1830 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -58,7 +58,8 @@ protocol:
 
 While the IO version reads and deserializes a line back to a Proto,
 the shell script version of this returns a Var, which has the newly
-read line in it, not yet deserialized.
+read line in it, not yet deserialized. Why the difference? Well, Haskell
+has data types, and shell does not ...
 
 ## speaking the protocol
 

indent
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
index 3dc7351..ab72b3a 100644
--- a/blog/entry/shell_monad_day_3.mdwn
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -193,29 +193,29 @@ scripts by hand anymore! :)
 
 ## the pretty-printed shell program
 
-#!/bin/sh
-set -x
-_handler () { :
-	_v=
-	read _v
-	case "${_v%%\ *}" in FOO) :
-		echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2
-	;; BAR) :
-		echo 'yay, I got a Bar' >&2
-	;; BAZ) :
-		for _x in $(seq 1 "${_v#[!\ ]*[\ ]}")
-		do :
-			echo 'yay, I got a Baz' "$_x" >&2
-		done
-	;; *) :
-		echo 'unknown protocol command' "${_v%%\ *}" >&2
-		false
-	;; esac
-}
-echo 'FOO starting up'
-_handler
-echo 'BAR '
-_handler
+	#!/bin/sh
+	set -x
+	_handler () { :
+		_v=
+		read _v
+		case "${_v%%\ *}" in FOO) :
+			echo 'yay, I got a Foo' "${_v#[!\ ]*[\ ]}" >&2
+		;; BAR) :
+			echo 'yay, I got a Bar' >&2
+		;; BAZ) :
+			for _x in $(seq 1 "${_v#[!\ ]*[\ ]}")
+			do :
+				echo 'yay, I got a Baz' "$_x" >&2
+			done
+		;; *) :
+			echo 'unknown protocol command' "${_v%%\ *}" >&2
+			false
+		;; esac
+	}
+	echo 'FOO starting up'
+	_handler
+	echo 'BAR '
+	_handler
 	
 ## the one-liner shell program
 	

blog update
diff --git a/blog/entry/shell_monad_day_3.mdwn b/blog/entry/shell_monad_day_3.mdwn
new file mode 100644
index 0000000..3dc7351
--- /dev/null
+++ b/blog/entry/shell_monad_day_3.mdwn
@@ -0,0 +1,222 @@
+I have been hard at work on the
+[shell-monad](http://hackage.haskell.org/package/shell-monad/)
+ever since it was born on Christmas Eve. It's now up to 820 lines of code,
+and has nearly comprehensive coverage of all shell features.
+
+Time to use it for something interesting! Let's make a shell script and a
+haskell program that both speak a simple protocol. This kind of thing could
+be used by [[code/propellor]] when it's deploying itself to a new host. The
+haskell program can ssh to a remote host and run the shell program, and
+talk back and forth over stdio with it, using the protocol they both speak.
+
+[[!toc]]
+
+## abstract beginnings
+
+First, we'll write a data type for the commands in the protocol.
+
+	data Proto
+		= Foo String
+		| Bar
+		| Baz Integer
+		deriving (Show)
+
+Now, let's go type class crazy! 
+
+	class Monad t => OutputsProto t where
+		output :: Proto -> t ()
+	
+	instance OutputsProto IO where
+		output = putStrLn . fromProto
+	
+So far, nothing interesting; this makes the IO monad an instance of the
+`OutputsProto` type class, and gives a simple implementation to output a
+line of the protocol.
+
+	instance OutputsProto Script where
+		output = cmd "echo" . fromProto
+
+Now it gets interesting. The Script monad is now also a member of the
+`OutputsProto`. To output a line of the protocol, it just uses echo.
+Yeah -- shell code is a member of a haskell type class. Awesome -- most
+abstract shell code evar!
+
+Similarly, we can add another type class for monads that can input the
+protocol:
+
+	class Monad t => InputsProto t p where
+		input :: t p
+	
+	instance InputsProto IO Proto where
+		input = toProto <$> readLn
+	
+	instance InputsProto Script Var where
+		input = do
+			v <- newVar ()
+			readVar v
+			return v
+
+While the IO version reads and deserializes a line back to a Proto,
+the shell script version of this returns a Var, which has the newly
+read line in it, not yet deserialized.
+
+## speaking the protocol
+
+Now we have enough groundwork to write haskell code in the IO monad that
+speaks the protocol in arbitrary ways. For example:
+
+	protoExchangeIO :: Proto -> IO Proto
+	protoExchangeIO p = do
+		output p
+		input
+	
+	fooIO :: IO ()
+	fooIO = do
+		resp <- protoExchangeIO (Foo "starting up")
+		-- etc
+
+But that's trivial and uninteresting. The interesting part is making the
+shell program speak the protocol, including doing various things when it
+receives the commands.
+
+	foo :: Script ()
+	foo = do
+		stopOnFailure True
+		handler <- func (NamedLike "handler") $
+			handleProto =<< input
+		output (Foo "starting up")
+		handler
+		output Bar
+		handler
+	
+	handleFoo :: Var -> Script ()
+	handleFoo v = toStderr $ cmd "echo" "yay, I got a Foo" v
+	
+	handleBar :: Script ()
+	handleBar = toStderr $ cmd "echo" "yay, I got a Bar"
+	
+	handleBaz :: Var -> Script ()
+	handleBaz num = forCmd (cmd "seq" (Val (1 :: Int)) num) $
+		toStderr . cmd "echo" "yay, I got a Baz"
+
+## serialization
+
+I've left out a few serialization functions. `fromProto` is used in both
+instances of OutputsProto. The haskell program and the script will both use
+this to serialize Proto.
+
+	fromProto :: Proto -> String
+	fromProto (Foo s) = pFOO ++ " " ++ s
+	fromProto Bar = pBAR ++ " "
+	fromProto (Baz i) = pBAZ ++ " " ++ show i
+	
+	pFOO, pBAR, pBAZ :: String
+	(pFOO, pBAR, pBAZ) = ("FOO", "BAR", "BAZ")
+
+And here's the haskell function to convert the other direction, which was also
+used earlier.
+
+	toProto :: String -> Proto
+	toProto s = case break (== ' ') s of
+		(w, ' ':rest)
+			| w == pFOO -> Foo rest
+			| w == pBAR && null rest -> Bar
+			| w == pBAZ -> Baz (read rest)
+			| otherwise -> error $ "unknown protocol command: " ++ w
+		(_, _) -> error "protocol splitting error"
+
+We also need a version of that written in the Script monad. Here it is.
+Compare and contrast the function below with the one above. They're
+really quite similar. (Sadly, not so similar to allow refactoring out a common
+function..)
+
+	handleProto :: Var -> Script ()
+	handleProto v = do
+		w <- getProtoCommand v
+		let rest = getProtoRest v
+		caseOf w
+			[ (quote (T.pack pFOO), handleFoo =<< rest)
+			, (quote (T.pack pBAR), handleBar)
+			, (quote (T.pack pBAZ), handleBaz =<< rest)
+			, (glob "*", do
+				toStderr $ cmd "echo" "unknown protocol command" w
+				cmd "false"
+			  )
+			]
+
+Both `toProto` and  `handleProto` split the incoming line apart into the
+first word, and the rest of the line, then match the first word against the
+commands in the protocol, and dispatches to appropriate actions. So,
+how do we split a variable apart like that in the Shell monad? Like this...
+
+	getProtoCommand :: Var -> Script Var
+	getProtoCommand v = trimVar LongestMatch FromEnd v (glob " *")
+	
+	getProtoRest :: Var -> Script Var
+	getProtoRest v = trimVar ShortestMatch FromBeginning v (glob "[! ]*[ ]")
+
+(This could probably be improved by using a DSL to generate the globs
+too..)
+
+## conclusion
+
+And finally, here's a `main` to generate the shell script!
+
+	main :: IO ()
+	main = T.writeFile "protocol.sh" $ script foo
+
+The pretty-printed shell script that produces is not very interesting,
+but I'll include it at the end for completeness. More interestingly for the
+purposes of sshing to a host and running the command there, we can use
+`linearScript` to generate a version of the script that's all contained on
+a single line. Also included below.
+
+I could easily have written the pretty-printed version of the shell script
+in twice the time that it took to write the haskell program that generates
+it and also speaks the protocol itself.
+
+I would certianly have had to test the hand-written shell script repeatedly.
+Code like `for _x in $(seq 1 "${_v#[!\ ]*[\ ]}")` doesn't just write and
+debug itself. (Until now!)
+
+But, the generated scrpt worked 100% on the first try! Well, it worked as
+soon as I got the Haskell program to compile...
+
+But the best part is that the Haskell program and the shell script
+don't just speak the same protocol. They both rely on the same
+definition of Proto. So this is fairly close to the kind of type-safe
+protocol serialization that Fay provides, when compiling Haskell to
+javascript.
+
+I'm getting the feeling that I won't be writing too many nontrivial shell
+scripts by hand anymore! :)
+
+## the pretty-printed shell program

(Diff truncated)
update
diff --git a/code.mdwn b/code.mdwn
index 68243c1..bd7835a 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -23,6 +23,7 @@ In maintenance mode mostly, but I still have my hands in it somewhat.
 [[pdmenu]]
 [[filters]]
 [electrum-mnemonic](http://hackage.haskell.org/package/electrum-mnemonic)
+[shell-monad](http://hackage.haskell.org/package/shell-monad)
 [brainfuck-monad](http://hackage.haskell.org/package/brainfuck-monad)
 
 ## Past projects

one more
diff --git a/blog/entry/announcing_git-annex.mdwn b/blog/entry/announcing_git-annex.mdwn
index d4e4d0b..8f182d6 100644
--- a/blog/entry/announcing_git-annex.mdwn
+++ b/blog/entry/announcing_git-annex.mdwn
@@ -23,3 +23,4 @@ uploaded to Debian shortly; or
 [git clone it](http://git-annex.branchable.com/download/).
 
 [[!meta title="announcing git-annex"]]
+[[!tag haskell]]

more
diff --git a/blog/entry/Template_Haskell_on_impossible_architectures.mdwn b/blog/entry/Template_Haskell_on_impossible_architectures.mdwn
index 43d5876..846fdb0 100644
--- a/blog/entry/Template_Haskell_on_impossible_architectures.mdwn
+++ b/blog/entry/Template_Haskell_on_impossible_architectures.mdwn
@@ -114,3 +114,4 @@ PPS, Also, if you let this put you off Haskell in any way .. well, don't.
 You just might want to wait a year or so before doing Haskell on Android.
 
 [[!meta title="Template Haskell on impossible architectures"]]
+[[!tag haskell]]
diff --git a/blog/entry/a_year_of_haskell___40__not_really__41__.mdwn b/blog/entry/a_year_of_haskell___40__not_really__41__.mdwn
index bb7a799..7ab47e1 100644
--- a/blog/entry/a_year_of_haskell___40__not_really__41__.mdwn
+++ b/blog/entry/a_year_of_haskell___40__not_really__41__.mdwn
@@ -23,3 +23,5 @@ I won't bore you with why
 [connected](http://changelog.complete.org/archives/779-education)
 [in my](http://www.eyrie.org/~eagle/journal/2008-11/018.html)
 [head](http://www.last.fm/music/Prof.+Malcolm+David+Eckel/+listeners).
+
+[[!tag haskell]]
diff --git a/blog/entry/announcing_github-backup.mdwn b/blog/entry/announcing_github-backup.mdwn
index 6d996bd..a7e96c2 100644
--- a/blog/entry/announcing_github-backup.mdwn
+++ b/blog/entry/announcing_github-backup.mdwn
@@ -16,3 +16,4 @@ Available in Cabal now, in Debian maybe if someone packages
 [[!tag code/github-backup]]
 
 [[!meta title="announcing github-backup"]]
+[[!tag haskell]]
diff --git a/blog/entry/build_a_dynamic_webapp_in_Yesod_in_just_three_days.mdwn b/blog/entry/build_a_dynamic_webapp_in_Yesod_in_just_three_days.mdwn
index 9b2839e..b481a39 100644
--- a/blog/entry/build_a_dynamic_webapp_in_Yesod_in_just_three_days.mdwn
+++ b/blog/entry/build_a_dynamic_webapp_in_Yesod_in_just_three_days.mdwn
@@ -98,3 +98,4 @@ I also see a lot of potential in Yesod to improve from where it is.
 [[!tag haskell yesod webapp braindump]]
 
 [[!meta title="build a dynamic webapp in Yesod in just three days"]]
+[[!tag haskell]]
diff --git a/blog/entry/case_study:_adding_box.com_support_to_git-annex.mdwn b/blog/entry/case_study:_adding_box.com_support_to_git-annex.mdwn
index eb97801..a89febd 100644
--- a/blog/entry/case_study:_adding_box.com_support_to_git-annex.mdwn
+++ b/blog/entry/case_study:_adding_box.com_support_to_git-annex.mdwn
@@ -82,3 +82,4 @@ Would someone like to fund my time to add a dropbox special remote to git-annex?
 [[!tag haskell code/git-annex consulting cloud]]
 
 [[!meta title="case study: adding box.com support to git-annex"]]
+[[!tag haskell]]
diff --git a/blog/entry/debugging_musings.mdwn b/blog/entry/debugging_musings.mdwn
index 9d354ef..df200b2 100644
--- a/blog/entry/debugging_musings.mdwn
+++ b/blog/entry/debugging_musings.mdwn
@@ -51,3 +51,4 @@ assumption is that the runtime environment just works, but I by now may
 have over-challenged that assumption. :)
 
 [[!meta title="debugging musings"]]
+[[!tag haskell]]
diff --git a/blog/entry/first_real_Haskell_program.mdwn b/blog/entry/first_real_Haskell_program.mdwn
index 3d3a6dd..df7ae6a 100644
--- a/blog/entry/first_real_Haskell_program.mdwn
+++ b/blog/entry/first_real_Haskell_program.mdwn
@@ -71,3 +71,4 @@ the input handle! Which is problimatic if you were going to use the file
 after you locked it..
 
 [[!meta title="first real Haskell program"]]
+[[!tag haskell]]
diff --git a/blog/entry/ghc_threaded_runtime_gotchas.mdwn b/blog/entry/ghc_threaded_runtime_gotchas.mdwn
index 21cb8d3..ad3963c 100644
--- a/blog/entry/ghc_threaded_runtime_gotchas.mdwn
+++ b/blog/entry/ghc_threaded_runtime_gotchas.mdwn
@@ -100,3 +100,4 @@ wide-ranging suite of thread communications data types (`MVar`, `Chan`,
 `QSemN`, `TMVar`, `SampleVar`, etc) have made developing a complex threaded
 program something I feel comfortable doing for the first time, in any
 language.
+[[!tag haskell]]
diff --git a/blog/entry/happy_haskell_hacker.mdwn b/blog/entry/happy_haskell_hacker.mdwn
index e9bbbb4..a66bc33 100644
--- a/blog/entry/happy_haskell_hacker.mdwn
+++ b/blog/entry/happy_haskell_hacker.mdwn
@@ -116,3 +116,4 @@ before, but it's very nice that it makes it so clean, easy, and generic.
 [[!tag code haskell]]
 
 [[!meta title="happy haskell hacker"]]
+[[!tag haskell]]
diff --git a/blog/entry/haskell_and_xmonad.mdwn b/blog/entry/haskell_and_xmonad.mdwn
index 5a26f81..43617f4 100644
--- a/blog/entry/haskell_and_xmonad.mdwn
+++ b/blog/entry/haskell_and_xmonad.mdwn
@@ -81,3 +81,5 @@ My current set of gripes with xmonad is small:
   type Haskell into the window manager. I rarely speak `lua` to `awesome` or
   `ion3`, but it's nice to have the ability there. I *think* it should be
   possible to do this with Haskell (see `ghci`).
+
+[[!tag haskell]]
diff --git a/blog/entry/haskell_baby_steps.mdwn b/blog/entry/haskell_baby_steps.mdwn
index 31d7d32..de18eac 100644
--- a/blog/entry/haskell_baby_steps.mdwn
+++ b/blog/entry/haskell_baby_steps.mdwn
@@ -32,3 +32,4 @@ error message and google took longer than figuring out how to write the rest
 of the program. :-(
 
 [[discussion]]
+[[!tag haskell]]
diff --git a/blog/entry/how_I_wrote_init_by_accident.mdwn b/blog/entry/how_I_wrote_init_by_accident.mdwn
index 1edb65e..946a2ac 100644
--- a/blog/entry/how_I_wrote_init_by_accident.mdwn
+++ b/blog/entry/how_I_wrote_init_by_accident.mdwn
@@ -54,3 +54,4 @@ from propellor.
 
 [[!meta title="how I wrote init by accident"]]
 [[!tag propellor]]
+[[!tag haskell]]
diff --git a/blog/entry/more_on_ghc_filename_encodings.mdwn b/blog/entry/more_on_ghc_filename_encodings.mdwn
index 44f9842..4fadd24 100644
--- a/blog/entry/more_on_ghc_filename_encodings.mdwn
+++ b/blog/entry/more_on_ghc_filename_encodings.mdwn
@@ -50,3 +50,4 @@ Language bugs.. gotta love em.
 [[!tag haskell]]
 
 [[!meta title="more on ghc filename encodings"]]
+[[!tag haskell]]
diff --git a/blog/entry/no_longer_a_perl_programmer.mdwn b/blog/entry/no_longer_a_perl_programmer.mdwn
index c5113e5..006efd7 100644
--- a/blog/entry/no_longer_a_perl_programmer.mdwn
+++ b/blog/entry/no_longer_a_perl_programmer.mdwn
@@ -49,3 +49,4 @@ Of course if Bradley Kuhn is right and
 I know what I'll be doing come the unix rollover in 2038. ;)
 
 [[!meta title="no longer a perl programmer"]]
+[[!tag haskell]]
diff --git a/blog/entry/on_haskell.mdwn b/blog/entry/on_haskell.mdwn
index 7737788..7e7971f 100644
--- a/blog/entry/on_haskell.mdwn
+++ b/blog/entry/on_haskell.mdwn
@@ -18,3 +18,4 @@ style=bar barwidth=2 barspacing=1 height=13]]
 
 [[discussion]]
 [[!meta date="Sun Aug 12 05:50:05 2007 +0000"]]
+[[!tag haskell]]
diff --git a/blog/entry/please_build_a_haskell_to_perl_compiler.mdwn b/blog/entry/please_build_a_haskell_to_perl_compiler.mdwn
index 600bae0..7cab4ea 100644
--- a/blog/entry/please_build_a_haskell_to_perl_compiler.mdwn
+++ b/blog/entry/please_build_a_haskell_to_perl_compiler.mdwn
@@ -27,3 +27,4 @@ be forwarded to the EFF instead.
 [[!tag haskell]]
 
 [[!meta title="please build a haskell to perl compiler"]]
+[[!tag haskell]]
diff --git a/blog/entry/three_thousand_lines_of_Haskell.mdwn b/blog/entry/three_thousand_lines_of_Haskell.mdwn
index 9d8b19c..323c8c0 100644
--- a/blog/entry/three_thousand_lines_of_Haskell.mdwn
+++ b/blog/entry/three_thousand_lines_of_Haskell.mdwn
@@ -90,3 +90,4 @@ other random impressions..
 [[!tag braindump haskell]]
 
 [[!meta title="three thousand lines of Haskell"]]
+[[!tag haskell]]
diff --git a/blog/entry/unicode_ate_my_homework.mdwn b/blog/entry/unicode_ate_my_homework.mdwn
index 9868f05..3e8cf0e 100644
--- a/blog/entry/unicode_ate_my_homework.mdwn
+++ b/blog/entry/unicode_ate_my_homework.mdwn
@@ -108,3 +108,4 @@ Previously: [[unicode_eye_chart]] [[wanted_on_a_bumper_sticker]] [[abc]]
 [[!tag unicode haskell]]
 
 [[!meta title="unicode ate my homework"]]
+[[!tag haskell]]
diff --git a/blog/entry/watch_me_code_for_half_an_hour.mdwn b/blog/entry/watch_me_code_for_half_an_hour.mdwn
index 67ae924..5496c2a 100644
--- a/blog/entry/watch_me_code_for_half_an_hour.mdwn
+++ b/blog/entry/watch_me_code_for_half_an_hour.mdwn
@@ -17,3 +17,4 @@ subcommand implemented here into "--auto" options that can be passed to
 [[!poll 40 "watched it all, liked it" 8 "watched some, boring" 3 "too long for me" 14 "too haskell for me" 12 "not interested"]]
 
 [[!meta title="watch me program for half an hour"]]
+[[!tag haskell]]
diff --git a/blog/entry/xmonad.hs_for_the_Palm_Pre.mdwn b/blog/entry/xmonad.hs_for_the_Palm_Pre.mdwn
index 421cf5c..9528d2a 100644
--- a/blog/entry/xmonad.hs_for_the_Palm_Pre.mdwn
+++ b/blog/entry/xmonad.hs_for_the_Palm_Pre.mdwn
@@ -26,3 +26,4 @@ Thus, to start a new terminal, use "Menu a x"; to close a window use
 "Menu a c"; to change layout, use "Menu a space"; and you can read the
 rest of the bindings in
 [the config file](http://git.kitenet.net/?p=joey/home-plus.git;a=blob_plain;f=.xmonad/xmonad.hs.limpet;hb=HEAD).
+[[!tag haskell]]
diff --git a/blog/entry/xmonad_layouts_for_netbooks.mdwn b/blog/entry/xmonad_layouts_for_netbooks.mdwn
index 55b0ae5..20b5bde 100644
--- a/blog/entry/xmonad_layouts_for_netbooks.mdwn
+++ b/blog/entry/xmonad_layouts_for_netbooks.mdwn
@@ -277,3 +277,4 @@ Xmonad layout optimised for the small screen of a netbook:
 
 PS: Thanks to `#xmonad` regulars for always having the answer
 I need up their sleeves.
+[[!tag haskell]]
diff --git a/blog/haskell.mdwn b/blog/haskell.mdwn
index 3b4bb0b..393865d 100644
--- a/blog/haskell.mdwn
+++ b/blog/haskell.mdwn
@@ -1,3 +1,3 @@
 The most recent haskell-related posts to [[Joey]]'s [[blog]].
 
-[[!inline pages="blog/entry/* and link(haskell) and !*/Discussion" show=10]]
+[[!inline pages="blog/entry/* and link(haskell) and !*/Discussion" show=40]]

rename to expose tag
diff --git a/blog/entry/haskell.mdwn b/blog/entry/haskell.mdwn
deleted file mode 100644
index 0fed040..0000000
--- a/blog/entry/haskell.mdwn
+++ /dev/null
@@ -1,19 +0,0 @@
-I saw the old house on Haskell St. last week for the first time in forver.
-I could barely pick it out of the other houses on the block, it's so
-different now.
-
-I also, conincidentially, studied the haskell programming language a bit. I
-watched some talks that John Goerzen linked to, and I read several chapters of
-the "Gentle Introduction to Haskell". Which wasn't all that gentle. :-) I
-should have put off reading it until after the talks and after reading some
-other introductory examples.
-
-At least I have some motivation to learn haskell. I could never see any reason
-to bother learning python or ruby, since there's so few compelling differences
-between them and perl. I had begun to worry that I wasn't learning any new
-programming languages, so it's nice to have a new dot on this graph of
-[[languages]] I've learned since 1990:
-[[!sparkline 2 0 4 0 6 1 1 1 1 0 1 0 0 0 0 0 0 1(red)
-style=bar barwidth=2 barspacing=1 height=13]]
-
-[[discussion]]
diff --git a/blog/entry/haskell/discussion.mdwn b/blog/entry/haskell/discussion.mdwn
deleted file mode 100644
index ba318f9..0000000
--- a/blog/entry/haskell/discussion.mdwn
+++ /dev/null
@@ -1,50 +0,0 @@
-I also used to think there were no compelling differences between Perl and
-Python.  Then I was forced to learn Python for my new job.  Two weeks later
-I started a new hobby project for myself.  I started it in Perl, because
-I've been programming Perl for a couple of years, and Python for a couple
-of weeks (and I still didn't believe there were any compelling differences
-at that time).  After a couple of hours I gave up, rewrote it in Python,
-and never looked back.
-
-It's not just the language, but the traditions, ways of writing code, ways
-of designing APIs.  I'm significantly more productive in Python than in any
-other language I know (Pascal, C, C++, Java, Perl).
-
-I'm not trying to convince you to start learning Python right now; just to
-point out that it's hard to see what's compelling about Python without
-actually using it for a while.
-
-  -- Marius Gedminas (marius@gedmin.as)
-
-> While I haven't bothered to learn it, I'm familiar enough with python
-> that I can extrapolate how productive I would be in it if I invested, say
-> 5 years into learning and becoming extremely familiar with the language
-> (as I did with perl).
-> 
-> One benefit of python is that it might only take 3 years to get to that
-> point, thanks to things like the more regular calling conventions for
-> fuctions, less quirky syntax, better introspection, more standardised OO.
-> I might find learning all the libraries that much eaiser. Once I know
-> them in detail though, those things rarely matter, they might add a few
-> minutes to learning a new library, that's about all. And I suspect I'd
-> spend marginally more time typing than I do when writing perl, which
-> probably would balance that out pretty well.
-> 
-> Omitting the learning curve issues though, I see no significant
-> difference in productivity between python masters and perl masters. I
-> don't see anything in python or perl that would provide one, and I don't
-> see any evidence of one in the real world.
->
-> (The analysis is a bit different for ruby, and made with rather less
-> information, but my gut feeling is the same.)
-> 
-> One of the interesting things about haskell, to me, is that I can't even
-> make this kind of analysis about it yet. It's too different. Maybe
-> haskell masters crank out beautiful functional code with no bugs all day.
-> Maybe they spend all day tracking down hard to debug cases of infinite
-> recusion. The only statement I can make about them based on real world
-> observation is that they seem to think more formally than either perl or
-> python programmers, and that many of them seem to be focused more on
-> theory than on implementing real-world stuff.
-> 
-> --[[Joey]]
diff --git a/blog/entry/on_haskell.mdwn b/blog/entry/on_haskell.mdwn
new file mode 100644
index 0000000..7737788
--- /dev/null
+++ b/blog/entry/on_haskell.mdwn
@@ -0,0 +1,20 @@
+I saw the old house on Haskell St. last week for the first time in forver.
+I could barely pick it out of the other houses on the block, it's so
+different now.
+
+I also, conincidentially, studied the haskell programming language a bit. I
+watched some talks that John Goerzen linked to, and I read several chapters of
+the "Gentle Introduction to Haskell". Which wasn't all that gentle. :-) I
+should have put off reading it until after the talks and after reading some
+other introductory examples.
+
+At least I have some motivation to learn haskell. I could never see any reason
+to bother learning python or ruby, since there's so few compelling differences
+between them and perl. I had begun to worry that I wasn't learning any new
+programming languages, so it's nice to have a new dot on this graph of
+[[languages]] I've learned since 1990:
+[[!sparkline 2 0 4 0 6 1 1 1 1 0 1 0 0 0 0 0 0 1(red)
+style=bar barwidth=2 barspacing=1 height=13]]
+
+[[discussion]]
+[[!meta date="Sun Aug 12 05:50:05 2007 +0000"]]
diff --git a/blog/entry/on_haskell/discussion.mdwn b/blog/entry/on_haskell/discussion.mdwn
new file mode 100644
index 0000000..ba318f9
--- /dev/null
+++ b/blog/entry/on_haskell/discussion.mdwn
@@ -0,0 +1,50 @@
+I also used to think there were no compelling differences between Perl and
+Python.  Then I was forced to learn Python for my new job.  Two weeks later
+I started a new hobby project for myself.  I started it in Perl, because
+I've been programming Perl for a couple of years, and Python for a couple
+of weeks (and I still didn't believe there were any compelling differences
+at that time).  After a couple of hours I gave up, rewrote it in Python,
+and never looked back.
+
+It's not just the language, but the traditions, ways of writing code, ways
+of designing APIs.  I'm significantly more productive in Python than in any
+other language I know (Pascal, C, C++, Java, Perl).
+
+I'm not trying to convince you to start learning Python right now; just to
+point out that it's hard to see what's compelling about Python without
+actually using it for a while.
+
+  -- Marius Gedminas (marius@gedmin.as)
+
+> While I haven't bothered to learn it, I'm familiar enough with python
+> that I can extrapolate how productive I would be in it if I invested, say
+> 5 years into learning and becoming extremely familiar with the language
+> (as I did with perl).
+> 
+> One benefit of python is that it might only take 3 years to get to that
+> point, thanks to things like the more regular calling conventions for
+> fuctions, less quirky syntax, better introspection, more standardised OO.
+> I might find learning all the libraries that much eaiser. Once I know
+> them in detail though, those things rarely matter, they might add a few
+> minutes to learning a new library, that's about all. And I suspect I'd
+> spend marginally more time typing than I do when writing perl, which
+> probably would balance that out pretty well.
+> 
+> Omitting the learning curve issues though, I see no significant
+> difference in productivity between python masters and perl masters. I
+> don't see anything in python or perl that would provide one, and I don't
+> see any evidence of one in the real world.
+>
+> (The analysis is a bit different for ruby, and made with rather less
+> information, but my gut feeling is the same.)
+> 
+> One of the interesting things about haskell, to me, is that I can't even
+> make this kind of analysis about it yet. It's too different. Maybe
+> haskell masters crank out beautiful functional code with no bugs all day.
+> Maybe they spend all day tracking down hard to debug cases of infinite
+> recusion. The only statement I can make about them based on real world
+> observation is that they seem to think more formally than either perl or
+> python programmers, and that many of them seem to be focused more on
+> theory than on implementing real-world stuff.
+> 
+> --[[Joey]]

haskell feed
diff --git a/blog/entry/a_brainfuck_monad.mdwn b/blog/entry/a_brainfuck_monad.mdwn
index 941aa84..68dbba8 100644
--- a/blog/entry/a_brainfuck_monad.mdwn
+++ b/blog/entry/a_brainfuck_monad.mdwn
@@ -117,3 +117,4 @@ Of course, the real point is that "monad" and "brainfuck" so obviously
 belonged together that it would have been a crime not to write this.
 
 [[!meta title="a brainfuck monad"]]
+[[!tag haskell]]
diff --git a/blog/entry/adding_docker_support_to_propellor.mdwn b/blog/entry/adding_docker_support_to_propellor.mdwn
index 492bf30..0762f2b 100644
--- a/blog/entry/adding_docker_support_to_propellor.mdwn
+++ b/blog/entry/adding_docker_support_to_propellor.mdwn
@@ -70,3 +70,4 @@ not expressive enough.
 
 [[!meta title="adding docker support to propellor"]]
 [[!tag propellor]]
+[[!tag haskell]]
diff --git a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
index 9fcd34e..0671fd2 100644
--- a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
+++ b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
@@ -106,3 +106,4 @@ distribution you want. Patches welcomed...
 [[!tag propellor]]
 
 [[!meta title="clean OS reinstalls with propellor"]]
+[[!tag haskell]]
diff --git a/blog/entry/introducing_propellor.mdwn b/blog/entry/introducing_propellor.mdwn
index c05b524..97f6f28 100644
--- a/blog/entry/introducing_propellor.mdwn
+++ b/blog/entry/introducing_propellor.mdwn
@@ -96,3 +96,4 @@ to build just the thing you want without the cruft. Nice to have the latter!
 
 [[!tag propellor]]
 [[!meta date="Sun Mar 30 03:50:42 2014 -0400"]]
+[[!tag haskell]]
diff --git a/blog/entry/propelling_containers.mdwn b/blog/entry/propelling_containers.mdwn
index 0399a90..71b4a8e 100644
--- a/blog/entry/propelling_containers.mdwn
+++ b/blog/entry/propelling_containers.mdwn
@@ -1,4 +1,5 @@
 [[!tag propellor]]
+[[!tag haskell]]
 
 Propellor has supported docker containers for a "long" time, and it works
 great. This week I've worked on adding more container support.
diff --git a/blog/entry/propellor-driven_DNS_and_backups.mdwn b/blog/entry/propellor-driven_DNS_and_backups.mdwn
index 954539a..2ad9610 100644
--- a/blog/entry/propellor-driven_DNS_and_backups.mdwn
+++ b/blog/entry/propellor-driven_DNS_and_backups.mdwn
@@ -103,3 +103,4 @@ By the way, Propellor is now up to 3 thousand lines of code
 
 [[!meta title="propellor-driven DNS and backups"]]
 [[!tag propellor]]
+[[!tag haskell]]
diff --git a/blog/entry/propellor_introspection_for_DNS.mdwn b/blog/entry/propellor_introspection_for_DNS.mdwn
index 9bc8d0b..432ad05 100644
--- a/blog/entry/propellor_introspection_for_DNS.mdwn
+++ b/blog/entry/propellor_introspection_for_DNS.mdwn
@@ -94,3 +94,4 @@ main = do
 
 [[!meta title="propellor introspection for DNS"]]
 [[!tag propellor]]
+[[!tag haskell]]
diff --git a/blog/entry/propellor_is_d-i_2.0.mdwn b/blog/entry/propellor_is_d-i_2.0.mdwn
index 90b51e9..21d116c 100644
--- a/blog/entry/propellor_is_d-i_2.0.mdwn
+++ b/blog/entry/propellor_is_d-i_2.0.mdwn
@@ -66,3 +66,4 @@ and adding a few thousand lines of code to it.
 
 [[!meta title="propellor is d-i 2.0"]]
 [[!tag propellor]]
+[[!tag haskell]]
diff --git a/blog/entry/propellor_type-safe_reversions.mdwn b/blog/entry/propellor_type-safe_reversions.mdwn
index 62993c8..9545318 100644
--- a/blog/entry/propellor_type-safe_reversions.mdwn
+++ b/blog/entry/propellor_type-safe_reversions.mdwn
@@ -44,3 +44,4 @@ revertable, and others not:
 
 [[!meta title="propellor type-safe reversions"]]
 [[!tag propellor]]
+[[!tag haskell]]
diff --git a/blog/entry/shell_monad.mdwn b/blog/entry/shell_monad.mdwn
index 3069000..1f4d5d7 100644
--- a/blog/entry/shell_monad.mdwn
+++ b/blog/entry/shell_monad.mdwn
@@ -1,4 +1,5 @@
 [[!meta title="generating shell scripts from haskell using a shell monad"]]
+[[!tag haskell]]
 
 Shell script is the lingua franca of Unix, it's available everywhere and often
 the only reasonable choice to Get Stuff Done. But it's also clumsy and it's
diff --git a/blog/haskell.mdwn b/blog/haskell.mdwn
new file mode 100644
index 0000000..3b4bb0b
--- /dev/null
+++ b/blog/haskell.mdwn
@@ -0,0 +1,3 @@
+The most recent haskell-related posts to [[Joey]]'s [[blog]].
+
+[[!inline pages="blog/entry/* and link(haskell) and !*/Discussion" show=10]]

format
diff --git a/blog/entry/shell_monad.mdwn b/blog/entry/shell_monad.mdwn
index 995ffe2..3069000 100644
--- a/blog/entry/shell_monad.mdwn
+++ b/blog/entry/shell_monad.mdwn
@@ -45,7 +45,7 @@ When run, that haskell program generates this shell code.
 Which, while machine-generated, has nice indentation, and is generally
 pretty readable.
 
-[[!format shell """
+[[!format sh """
 #!/bin/sh
 f1 () { :
 	echo 'Ho, ho, ho!' 'Merry xmas!'

title
diff --git a/blog/entry/shell_monad.mdwn b/blog/entry/shell_monad.mdwn
index fe8738f..995ffe2 100644
--- a/blog/entry/shell_monad.mdwn
+++ b/blog/entry/shell_monad.mdwn
@@ -74,5 +74,3 @@ There's a lot of things that could be added to this library
 (`if`, `while`, redirection, etc), but I can already see using
 it in various parts of propellor and git-annex that need to generate
 shell code.
-
-[[!meta title="shell monad"]]

blog update
diff --git a/blog/entry/shell_monad.mdwn b/blog/entry/shell_monad.mdwn
new file mode 100644
index 0000000..fe8738f
--- /dev/null
+++ b/blog/entry/shell_monad.mdwn
@@ -0,0 +1,78 @@
+[[!meta title="generating shell scripts from haskell using a shell monad"]]
+
+Shell script is the lingua franca of Unix, it's available everywhere and often
+the only reasonable choice to Get Stuff Done. But it's also clumsy and it's
+easy to write unsafe shell scripts, that forget to quote variables, typo
+names of functions, etc.
+
+Wouldn't it be nice if we could write code in some better language,
+that generated nicely formed shell scripts and avoided such gotchas?
+Today, I've built a Haskell monad that can generate shell code.
+
+Here's a fairly involved example. This demonstrates several features,
+including the variadic `cmd`, the ability to define shell functions,
+to bind and use shell variables, to build pipes (with the `-:-` operator),
+and to factor out generally useful haskell functions like `pipeLess`
+and `promptFor` ...
+
+[[!format haskell """
+santa = script $ do
+	hohoho <- func $
+		cmd "echo" "Ho, ho, ho!" "Merry xmas!"
+	hohoho
+
+	promptFor "What's your name?" $ \name -> pipeLess $ do
+		cmd "echo" "Let's see what's in" (val name <> quote "'s") "stocking!"
+		forCmd (cmd "ls" "-1" (quote "/home/" <> val name)) $ \f -> do
+			cmd "echo" "a shiny new" f
+			hohoho
+
+	cmd "rm" "/table/cookies" "/table/milk"
+	hohoho
+
+pipeLess :: Script () -> Script ()
+pipeLess c = c -|- cmd "less"
+
+promptFor :: T.Text -> (Var -> Script ()) -> Script ()
+promptFor prompt cont = do
+	cmd "printf" (prompt <> " ")
+	var <- newVar "prompt"
+	readVar var
+	cont var
+"""]]
+
+When run, that haskell program generates this shell code.
+Which, while machine-generated, has nice indentation, and is generally
+pretty readable.
+
+[[!format shell """
+#!/bin/sh
+f1 () { :
+	echo 'Ho, ho, ho!' 'Merry xmas!'
+}
+f1
+printf 'What'"'"'s your name?  '
+read '_prompt1'
+(
+	echo 'Let'"'"'s see what'"'"'s in' "$_prompt1"''"'"'s' 'stocking!'
+	for _x1 in $(ls '-1' '/home/'"$_prompt1")
+	do :
+		echo 'a shiny new' "$_x1"
+		f1
+	done
+) | (
+	less
+)
+rm '/table/cookies' '/table/milk'
+f1
+"""]]
+
+Santa has already uploaded [shell-monad](http://hackage.haskell.org/package/shell-monad)
+to hackage and git.
+
+There's a lot of things that could be added to this library
+(`if`, `while`, redirection, etc), but I can already see using
+it in various parts of propellor and git-annex that need to generate
+shell code.
+
+[[!meta title="shell monad"]]

poll vote (watched it all, liked it)
diff --git a/blog/entry/watch_me_code_for_half_an_hour.mdwn b/blog/entry/watch_me_code_for_half_an_hour.mdwn
index 85dda47..67ae924 100644
--- a/blog/entry/watch_me_code_for_half_an_hour.mdwn
+++ b/blog/entry/watch_me_code_for_half_an_hour.mdwn
@@ -14,6 +14,6 @@ Not shown is the hour I spent the next day changing the "optimize"
 subcommand implemented here into "--auto" options that can be passed to
 [[code/git-annex]]'s get and drop commands.
 
-[[!poll 39 "watched it all, liked it" 8 "watched some, boring" 3 "too long for me" 14 "too haskell for me" 12 "not interested"]]
+[[!poll 40 "watched it all, liked it" 8 "watched some, boring" 3 "too long for me" 14 "too haskell for me" 12 "not interested"]]
 
 [[!meta title="watch me program for half an hour"]]

etckeeper website
diff --git a/code/etckeeper.mdwn b/code/etckeeper.mdwn
index 39776cc..f9a7f2b 100644
--- a/code/etckeeper.mdwn
+++ b/code/etckeeper.mdwn
@@ -7,9 +7,7 @@ such as the permissions of `/etc/shadow`. It's quite modular and
 configurable, while also being simple to use if you understand the basics
 of working with revision control.
 
-etckeeper is available in git at `git://git.kitenet.net/etckeeper`, or
-[in gitweb](http://git.kitenet.net/?p=etckeeper.git). It's packaged in
-Debian, Ubuntu, Fedora, etc.
+<http://etckeeper.branchable.com/>
 
 ## News
 
diff --git a/code/etckeeper/news/new_website.mdwn b/code/etckeeper/news/new_website.mdwn
new file mode 100644
index 0000000..4f50548
--- /dev/null
+++ b/code/etckeeper/news/new_website.mdwn
@@ -0,0 +1,3 @@
+etckeeper now has a website at <http://etckeeper.branchable.com/>.
+
+New releases will be posted there; please update your RSS subscriptions.
diff --git a/code/etckeeper/news/version_1.12.mdwn b/code/etckeeper/news/version_1.12.mdwn
deleted file mode 100644
index 54084cf..0000000
--- a/code/etckeeper/news/version_1.12.mdwn
+++ /dev/null
@@ -1,7 +0,0 @@
-etckeeper 1.12 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Portability fixes. Thanks, Harald Dunkel.
-   * Add support for pushing to multiple remote repositories.
-     Thanks, Rouben.
-   * Fix handling of git ignores like dir/*
-     Thanks, Pim van den Berg"""]]
\ No newline at end of file
diff --git a/code/etckeeper/news/version_1.13.mdwn b/code/etckeeper/news/version_1.13.mdwn
deleted file mode 100644
index 1bd3b79..0000000
--- a/code/etckeeper/news/version_1.13.mdwn
+++ /dev/null
@@ -1,7 +0,0 @@
-etckeeper 1.13 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Ignore check-mk-agent-logwatch's FHS violating
-     /etc/check\_mk/logwatch.state. Closes: #[753903](http://bugs.debian.org/753903)
-   * Only allow [-a-z\_] in etckeeper commands to avoid any possible directory
-     traversal etc issues.
-   * update-ignore, uninit: Fix parsing of ignore files containing '\'"""]]
\ No newline at end of file
diff --git a/code/etckeeper/news/version_1.14.mdwn b/code/etckeeper/news/version_1.14.mdwn
deleted file mode 100644
index e5789d3..0000000
--- a/code/etckeeper/news/version_1.14.mdwn
+++ /dev/null
@@ -1,9 +0,0 @@
-etckeeper 1.14 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Handle failure to commit in post-install, pre-install by showing a
-     warning, rather than propigating the error to apt.
-     This avoids breaking the apt run when eg, git is misconfigured and
-     cannot commit.
-     pre-install already did this when it was able to use debconf to display a
-     message, but now debconf is not used, and it always behaves this way.
-     Closes: #[760011](http://bugs.debian.org/760011)"""]]
\ No newline at end of file
diff --git a/code/etckeeper/news/version_1.15.mdwn b/code/etckeeper/news/version_1.15.mdwn
deleted file mode 100644
index 4934b76..0000000
--- a/code/etckeeper/news/version_1.15.mdwn
+++ /dev/null
@@ -1,4 +0,0 @@
-etckeeper 1.15 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Recommend cron-daemon, rather than cron, as etckeeper only needs
-     cron.daily functionality. Closes: #[762721](http://bugs.debian.org/762721)"""]]
\ No newline at end of file
diff --git a/code/etckeeper/news/version_1.16.mdwn b/code/etckeeper/news/version_1.16.mdwn
deleted file mode 100644
index 91d93b4..0000000
--- a/code/etckeeper/news/version_1.16.mdwn
+++ /dev/null
@@ -1,6 +0,0 @@
-etckeeper 1.16 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Added support for Fedora's DNF highlevel package manager.
-     Thanks, Peter Listiak and Petr Spacek.
-   * Add architecture info to dpkg list-installed. Closes: #[768145](http://bugs.debian.org/768145)
-   * Orphaned the Debian package."""]]
\ No newline at end of file

add news item for github-backup 1.20141222
diff --git a/code/github-backup/news/version_1.20140807.mdwn b/code/github-backup/news/version_1.20140807.mdwn
deleted file mode 100644
index a71336c..0000000
--- a/code/github-backup/news/version_1.20140807.mdwn
+++ /dev/null
@@ -1,4 +0,0 @@
-github-backup 1.20140807 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Fix build with github 0.9.
-   * Fix creation of github branch."""]]
\ No newline at end of file
diff --git a/code/github-backup/news/version_1.20141222.mdwn b/code/github-backup/news/version_1.20141222.mdwn
new file mode 100644
index 0000000..b429657
--- /dev/null
+++ b/code/github-backup/news/version_1.20141222.mdwn
@@ -0,0 +1,8 @@
+github-backup 1.20141222 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Added gitriddance(1), a utility to close all issues and pull requests,
+     for repos that don't want to be bothered with GitHub's proprietary
+     issue tracker.
+   * gitriddance depends on github 0.13.1, which has bug fixes
+     for posting comments.
+   * Various updates to internal git and utility libraries shared with git-annex."""]]
\ No newline at end of file

add
diff --git a/pics/brazil/2014/meeting-in-terravista.jpeg b/pics/brazil/2014/meeting-in-terravista.jpeg
new file mode 100644
index 0000000..deb8130
Binary files /dev/null and b/pics/brazil/2014/meeting-in-terravista.jpeg differ

update
diff --git a/code.mdwn b/code.mdwn
index 93302ef..68243c1 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -6,22 +6,24 @@ occasionally basic websites about my software.
 The stuff that's swapped into my local cache at the moment.
 
 [[git-annex]]
-[[ikiwiki]]
 [[propellor]]
 [[myrepos|mr]]
 [[etckeeper]]
+[[ikiwiki]]
 [[moreutils]]
 [[ikiwiki-hosting]]
 [[github-backup]]
-[[mpdtoys]]
 
 ## Less active projects
 
 In maintenance mode mostly, but I still have my hands in it somewhat.
 
+[[mpdtoys]]
 [[Words2Nums]]
 [[pdmenu]]
 [[filters]]
+[electrum-mnemonic](http://hackage.haskell.org/package/electrum-mnemonic)
+[brainfuck-monad](http://hackage.haskell.org/package/brainfuck-monad)
 
 ## Past projects
 

comment
diff --git a/blog/entry/a_brainfuck_monad/comment_3_156c49d4a06acddecdb4f6a74a643f52._comment b/blog/entry/a_brainfuck_monad/comment_3_156c49d4a06acddecdb4f6a74a643f52._comment
new file mode 100644
index 0000000..6cc4291
--- /dev/null
+++ b/blog/entry/a_brainfuck_monad/comment_3_156c49d4a06acddecdb4f6a74a643f52._comment
@@ -0,0 +1,45 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""alloc"""
+ date="2014-12-12T17:42:51Z"
+ content="""
+Instead of the constants hack, it's useful to define a stack-based
+function call model in brainfuck. This alloc higher-level function
+implements that, and is simplifying the code significantly.
+
+<pre>
+-- | For higher-level programming in brainfuck, it's useful to have a way
+-- to run a function, while allocating a memory cell, which is initialized
+-- to contain 0.
+--
+-- This and many of the functions below assume that
+-- cells to the left are in use, while cells to the right
+-- are unused and may contain any data. Higher-level functions should
+-- generally avoid changing the current cell, and should instead alloc
+-- a new one to use.
+alloc :: BrainFuck a -> BrainFuck a
+alloc a = do
+        next
+        zero
+        cell <- addr
+        r <- a
+        setAddr cell
+        prev
+        return r
+</pre>
+
+Using alloc, we can build a nicer loopFrom, etc.
+
+<pre>
+-- | Allocates a cell and uses it as the loop counter, starting from 
+-- the provided value. The action will continue running in a loop until
+-- it decrements the counter to 0.
+loopFrom :: Int -> (DataPointer -> BrainFuck ()) -> BrainFuck ()
+loopFrom n a = alloc $ do
+        i <- addr
+        add n
+        loopUnless0 $ do
+                a i
+                setAddr i
+</pre>
+"""]]

Added a comment: Ah, so that’s where the “useless” numbers come from…
diff --git a/blog/entry/a_brainfuck_monad/comment_3_435056729f4e0dc16e01a8110e1baa64._comment b/blog/entry/a_brainfuck_monad/comment_3_435056729f4e0dc16e01a8110e1baa64._comment
new file mode 100644
index 0000000..166ec49
--- /dev/null
+++ b/blog/entry/a_brainfuck_monad/comment_3_435056729f4e0dc16e01a8110e1baa64._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="http://mirsolutions.de/"
+ nickname="mirabilos"
+ subject="Ah, so that’s where the “useless” numbers come from…"
+ date="2014-12-12T12:12:22Z"
+ content="""
+… I had wondered.
+
+And it’s probably saying something about me that I find the brainfuck output more legible than the Haskell input ☺
+
+(But only that I speak only one of the two languages.)
+"""]]

innaccurate
diff --git a/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment b/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment
deleted file mode 100644
index 06e827f..0000000
--- a/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment
+++ /dev/null
@@ -1,13 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 3"""
- date="2014-12-12T08:10:37Z"
- content="""
-Ah, here's a way to avoid the mess with the constants:
-
-<pre>
--- | Fills the current data cell with zero.
-zero :: BrainFuck ()
-zero = loopUnless0 decr
-</pre>
-"""]]

typo
diff --git a/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment b/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment
index ec0eee8..06e827f 100644
--- a/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment
+++ b/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment
@@ -8,6 +8,6 @@ Ah, here's a way to avoid the mess with the constants:
 <pre>
 -- | Fills the current data cell with zero.
 zero :: BrainFuck ()
-zero n = loopUnless0 decr
+zero = loopUnless0 decr
 </pre>
 """]]

comment
diff --git a/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment b/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment
new file mode 100644
index 0000000..ec0eee8
--- /dev/null
+++ b/blog/entry/a_brainfuck_monad/comment_3_01fd8cad33389e3a614d7686f9217888._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2014-12-12T08:10:37Z"
+ content="""
+Ah, here's a way to avoid the mess with the constants:
+
+<pre>
+-- | Fills the current data cell with zero.
+zero :: BrainFuck ()
+zero n = loopUnless0 decr
+</pre>
+"""]]

comment
diff --git a/blog/entry/a_brainfuck_monad/comment_1_0c53bef9e32440f6296f0d58ba89118e._comment b/blog/entry/a_brainfuck_monad/comment_1_0c53bef9e32440f6296f0d58ba89118e._comment
new file mode 100644
index 0000000..ab45f40
--- /dev/null
+++ b/blog/entry/a_brainfuck_monad/comment_1_0c53bef9e32440f6296f0d58ba89118e._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""more example code"""
+ date="2014-12-12T06:46:32Z"
+ content="""
+I posted several examples, include a size-optimised "hello world" program
+in this thread:
+<https://identi.ca/joeyh/note/htuYlTRfRnKLGud0xCOcmg>
+"""]]

Added a comment: Unlambda
diff --git a/blog/entry/a_brainfuck_monad/comment_1_eccbec82a396057fd7c67d3e73095560._comment b/blog/entry/a_brainfuck_monad/comment_1_eccbec82a396057fd7c67d3e73095560._comment
new file mode 100644
index 0000000..ac526dd
--- /dev/null
+++ b/blog/entry/a_brainfuck_monad/comment_1_eccbec82a396057fd7c67d3e73095560._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawk9j9q_rKhvu7DAecZp-oEGRQmT3bvymVc"
+ nickname="Geoffrey"
+ subject="Unlambda"
+ date="2014-12-12T05:56:47Z"
+ content="""
+Wouldn't an Unlambda monad be more Haskell-ish? :)
+"""]]

foo
diff --git a/blog/entry/a_brainfuck_monad.mdwn b/blog/entry/a_brainfuck_monad.mdwn
index d647e00..941aa84 100644
--- a/blog/entry/a_brainfuck_monad.mdwn
+++ b/blog/entry/a_brainfuck_monad.mdwn
@@ -101,7 +101,7 @@ loop a = do
 """]]
 
 I haven't bothered to make sure that the constants are really constant,
-but that could be done. It would just need a Contaol.Monad.BrainFuck.Safe
+but that could be done. It would just need a Control.Monad.BrainFuck.Safe
 module, that uses a different monad, in which `incr` and `decr` and `input`
 don't do anything when the data pointer is pointing at a constant.
 Or, perhaps this could be statically checked at the type level, with

foo
diff --git a/blog/entry/a_brainfuck_monad.mdwn b/blog/entry/a_brainfuck_monad.mdwn
index 394a398..d647e00 100644
--- a/blog/entry/a_brainfuck_monad.mdwn
+++ b/blog/entry/a_brainfuck_monad.mdwn
@@ -84,7 +84,7 @@ program with these constants set up at the beginning.
 It just generates the brainfuck code for a series of ASCII art fishes:
 `>+>++>+++>++++>+++++>++++++>+++++++>++++++++>`
 
-With the fishes^Wconstants in place, it's possible to write a more useful
+With the fishes\^Wconstants in place, it's possible to write a more useful
 `loop`. Notice how the data pointer location is saved at the beginning, and
 restored inside the loop body. This ensures that the provided BrainFuck
 action doesn't stomp on our constants.

foo
diff --git a/blog/entry/a_brainfuck_monad.mdwn b/blog/entry/a_brainfuck_monad.mdwn
index 7830c8d..394a398 100644
--- a/blog/entry/a_brainfuck_monad.mdwn
+++ b/blog/entry/a_brainfuck_monad.mdwn
@@ -43,7 +43,8 @@ addr = BrainFuck $ \loc -> ([], loc, loc)
 
 Having the data pointer address available 
 allows writing some useful utility functions like this one,
-which uses the `next` (`>`) and `prev` (`<`) instructions.
+which uses the `next` (brainfuck opcode `>`) and `prev` (brainfuck opcode `<`)
+instructions.
 
 [[!format haskell """
 -- Moves the data pointer to a specific address.

typo
diff --git a/blog/entry/a_brainfuck_monad.mdwn b/blog/entry/a_brainfuck_monad.mdwn
index 6cf491a..7830c8d 100644
--- a/blog/entry/a_brainfuck_monad.mdwn
+++ b/blog/entry/a_brainfuck_monad.mdwn
@@ -23,7 +23,7 @@ Here's the brainfuck code that `demo` generates:
 `>+>++>+++>++++>+++++>++++++>+++++++>++++++++>++++++++++++++++++++++++++++++++<<<<<<<<[>>>>>>>>+.<<<<<<<<]`
 
 If you feed that into a brainfuck interpreter (I'm using `hsbrainfuck` for my
-testing), you'll find that it loops forever and prints out the each character,
+testing), you'll find that it loops forever and prints out each character,
 starting with space (32), in ASCIIbetical order.
 
 The implementation is quite similar to the ASM monad. The main differences

blog update
diff --git a/blog/entry/a_brainfuck_monad.mdwn b/blog/entry/a_brainfuck_monad.mdwn
new file mode 100644
index 0000000..6cf491a
--- /dev/null
+++ b/blog/entry/a_brainfuck_monad.mdwn
@@ -0,0 +1,118 @@
+Inspired by "[An ASM Monad](http://wall.org/~lewis/2013/10/15/asm-monad.html)",
+I've built a Haskell monad that produces
+[brainfuck programs](https://en.wikipedia.org/wiki/Brainfuck).
+The code for this monad is available
+[on hackage](http://hackage.haskell.org/package/brainfuck-monad),
+so `cabal install brainfuck-monad`.
+
+Here's a simple program written using this monad. See if you can guess
+what it might do:
+
+[[!format haskell """
+import Control.Monad.BrainFuck
+
+demo :: String
+demo = brainfuckConstants $ \constants -> do
+        add 31
+        forever constants $ do
+                add 1
+                output
+"""]]
+
+Here's the brainfuck code that `demo` generates:
+`>+>++>+++>++++>+++++>++++++>+++++++>++++++++>++++++++++++++++++++++++++++++++<<<<<<<<[>>>>>>>>+.<<<<<<<<]`
+
+If you feed that into a brainfuck interpreter (I'm using `hsbrainfuck` for my
+testing), you'll find that it loops forever and prints out the each character,
+starting with space (32), in ASCIIbetical order.
+
+The implementation is quite similar to the ASM monad. The main differences
+are that it builds a String, and that the BrainFuck monad keeps track
+of the current position of the data pointer (as brainfuck lacks any
+sane way to manipulate its instruction pointer).
+
+[[!format haskell """
+newtype BrainFuck a = BrainFuck (DataPointer -> ([Char], DataPointer, a))
+
+type DataPointer = Integer
+
+-- Gets the current address of the data pointer.
+addr :: BrainFuck DataPointer
+addr = BrainFuck $ \loc -> ([], loc, loc)
+"""]]
+
+Having the data pointer address available 
+allows writing some useful utility functions like this one,
+which uses the `next` (`>`) and `prev` (`<`) instructions.
+
+[[!format haskell """
+-- Moves the data pointer to a specific address.
+setAddr :: Integer -> BrainFuck ()
+setAddr n = do
+        a <- addr
+        if a > n
+                then prev >> setAddr n
+                else if a < n
+                        then next >> setAddr n
+                        else return ()
+"""]]
+
+Of course, brainfuck is a horrible language, designed to be nearly impossible
+to use. Here's the code to run a loop, but it's really hard to use this to
+build anything useful..
+
+[[!format haskell """
+-- The loop is only entered if the byte at the data pointer is not zero.
+-- On entry, the loop body is run, and then it loops when
+-- the byte at the data pointer is not zero.
+loopUnless0 :: BrainFuck () -> BrainFuck ()
+loopUnless0 a = do
+        open
+        a
+        close
+"""]]
+
+To tame brainfuck a bit, I decided to treat data addresses 0-8 as constants,
+which will contain the numbers 0-8. Otherwise, it's very hard to ensure
+that the data pointer is pointing at a nonzero number when you want
+to start a loop. (After all, brainfuck doesn't let you set data
+to some fixed value like 0 or 1!) 
+
+I wrote a little `brainfuckConstants` that runs a BrainFuck
+program with these constants set up at the beginning.
+It just generates the brainfuck code for a series of ASCII art fishes:
+`>+>++>+++>++++>+++++>++++++>+++++++>++++++++>`
+
+With the fishes^Wconstants in place, it's possible to write a more useful
+`loop`. Notice how the data pointer location is saved at the beginning, and
+restored inside the loop body. This ensures that the provided BrainFuck
+action doesn't stomp on our constants.
+
+[[!format haskell """
+-- Run an action in a loop, until it sets its data pointer to 0.
+loop :: BrainFuck () -> BrainFuck ()
+loop a = do
+	here <- addr
+	setAddr 1
+	loopUnless0 $ do
+		setAddr here
+		a
+"""]]
+
+I haven't bothered to make sure that the constants are really constant,
+but that could be done. It would just need a Contaol.Monad.BrainFuck.Safe
+module, that uses a different monad, in which `incr` and `decr` and `input`
+don't do anything when the data pointer is pointing at a constant.
+Or, perhaps this could be statically checked at the type level, with
+type level naturals. It's Haskell, we can make it safer if we want to. ;)
+
+So, not only does this BrainFuck monad allow writing brainfuck code using
+crazy haskell syntax, instead of crazy brainfuck syntax, but it
+allows doing some higher-level programming, building up a useful(!?) library
+of BrainFuck combinators and using them to generate brainfuck code
+you'd not want to try to write by hand.
+
+Of course, the real point is that "monad" and "brainfuck" so obviously
+belonged together that it would have been a crime not to write this.
+
+[[!meta title="a brainfuck monad"]]

Added a comment: Thanks!
diff --git a/blog/entry/podcasts_that_dont_suck_2014/comment_2_99e8f555f72b85e20f48a42a3ee73c13._comment b/blog/entry/podcasts_that_dont_suck_2014/comment_2_99e8f555f72b85e20f48a42a3ee73c13._comment
new file mode 100644
index 0000000..e4df2fd
--- /dev/null
+++ b/blog/entry/podcasts_that_dont_suck_2014/comment_2_99e8f555f72b85e20f48a42a3ee73c13._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawnlGmuCn25UzL_oQLm03QfW8vZV9dYHpSg"
+ nickname="Michael"
+ subject="Thanks!"
+ date="2014-12-11T06:45:50Z"
+ content="""
+I really enjoyed the last edition. Especially the Long Now seminars are amazing. Off to try your new recommendations. Looking forward to the 2015 edition.
+"""]]

Added a comment: You can cherry-pick
diff --git a/blog/entry/podcasts_that_dont_suck_2014/comment_1_76dc9dbae3c67f3eb6fb2da66fae2adf._comment b/blog/entry/podcasts_that_dont_suck_2014/comment_1_76dc9dbae3c67f3eb6fb2da66fae2adf._comment
new file mode 100644
index 0000000..0957089
--- /dev/null
+++ b/blog/entry/podcasts_that_dont_suck_2014/comment_1_76dc9dbae3c67f3eb6fb2da66fae2adf._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://launchpad.net/~skellat"
+ nickname="skellat"
+ subject="You can cherry-pick"
+ date="2014-12-10T04:34:44Z"
+ content="""
+My subscriptions list is available [on gpodder.net](https://gpodder.net/user/alpacaherder/subscriptions?token=eE3pZxQwVMJvKgimaAG6ITtY9u7k58oS) for now.
+"""]]

typo
diff --git a/blog/entry/podcasts_that_dont_suck_2014.mdwn b/blog/entry/podcasts_that_dont_suck_2014.mdwn
index 8104925..17bc499 100644
--- a/blog/entry/podcasts_that_dont_suck_2014.mdwn
+++ b/blog/entry/podcasts_that_dont_suck_2014.mdwn
@@ -34,7 +34,7 @@
   If you didn't before: You're welcome. :) Nuff said.
 
 * [Redecentralize](http://redecentralize.org/podcast/feed.rss): Interviews
-  with creatores of decentralized internet tools like Tahoe-LAFS, Ethereum,
+  with creators of decentralized internet tools like Tahoe-LAFS, Ethereum,
   Media Goblin, TeleHash. I just wish it went into more depth on protocols
   and how they work.
 

title
diff --git a/blog/entry/podcasts_that_dont_suck_2014.mdwn b/blog/entry/podcasts_that_dont_suck_2014.mdwn
index 51458ba..8104925 100644
--- a/blog/entry/podcasts_that_dont_suck_2014.mdwn
+++ b/blog/entry/podcasts_that_dont_suck_2014.mdwn
@@ -60,5 +60,3 @@ Seminars.
 PS: A nice podcatcher, for the technically inclined is
 [git-annex importfeed](http://git-annex.branchable.com/tips/downloading_podcasts/).
 Featuring list of feeds in a text file, and distributed podcatching!
-
-[[!meta title="podcasts that dont suck 2014"]]

format
diff --git a/blog/entry/podcasts_that_dont_suck_2014.mdwn b/blog/entry/podcasts_that_dont_suck_2014.mdwn
index d1a3d66..51458ba 100644
--- a/blog/entry/podcasts_that_dont_suck_2014.mdwn
+++ b/blog/entry/podcasts_that_dont_suck_2014.mdwn
@@ -9,14 +9,17 @@
   [description of when Niagra falls stopped](http://traffic.libsyn.com/memorypalace/Rush_and_Roar.mp3).
   I have listened to the entire back archive, and want *more*. Only downside
   is it's a looong time between new episodes.
+
 * [The Haskell Cast](http://www.haskellcast.com/feed.xml): Panel
   discussion with a guest, there is
   a lot of expertise amoung them and I'm often scrambling to keep up with
   the barrage of ideas. If this seems too tame, check out
   [The Type Theory Podcast](http://typetheorypodcast.com/feed/podcast) instead..
+
 * [Benjamen Walker's Theory of Everything](http://toe.prx.org/feed/): Only
   caught 2 episodes so far, but they've both been great. Short, punchy,
   quirky, geeky. Astoundingly good production values.
+
 * [Lightspeed magazine](http://www.lightspeedmagazine.com/feed/) and
   [Escape Pod](http://escapepod.org/feed/) blur together for me. Both
   feature 20-50 minute science fiction short stories, and occasionally
@@ -25,19 +28,24 @@
   for strange dreams. Two strongly contrasting examples:
   "[Observations About Eggs from the Man Sitting Next to Me on a Flight from Chicago, Illinois to Cedar Rapids, Iowa](http://www.podtrac.com/pts/redirect.mp3/www.lightspeedmagazine.com/podcasts/podcast_155-Observations_About_Eggs_from_etc-Carmen_Maria_Machado.mp3)"
   and "[Pay Phobetor](http://www.podtrac.com/pts/redirect.mp3/www.lightspeedmagazine.com/podcasts/podcast_191-Pay_Phobetor-Shale_Nelson.mp3)"
+
 * [Serial](http://feeds.serialpodcast.org/serialpodcast): You probably
   already know about this high profile TAL spinoff.
   If you didn't before: You're welcome. :) Nuff said.
+
 * [Redecentralize](http://redecentralize.org/podcast/feed.rss): Interviews
   with creatores of decentralized internet tools like Tahoe-LAFS, Ethereum,
   Media Goblin, TeleHash. I just wish it went into more depth on protocols
   and how they work.
+
 * [Love and Radio](http://feed.loveandradio.org/loveplusradio):
   This American Life squared and on acid.
+
 * [Debian & Stuff](http://www.debianandstuff.com/listen/?format=rss):
   My friend Asheesh and that guy I ate Thai food with once in Portland
   in a marvelously unfocused podcast that somehow connects everything
   up in the end. Only one episode so far; what are you guys waiting on? :P
+
 * [Hacker Public Radio](http://hackerpublicradio.org/hpr_ogg_rss.php):
   Anyone can upload an episode, and multiple episodes are published each
   week, which makes this a grab bag to pick and choose from occasionally.

blog update
diff --git a/blog/entry/podcasts_that_dont_suck_2014.mdwn b/blog/entry/podcasts_that_dont_suck_2014.mdwn
new file mode 100644
index 0000000..d1a3d66
--- /dev/null
+++ b/blog/entry/podcasts_that_dont_suck_2014.mdwn
@@ -0,0 +1,56 @@
+[[!meta title="podcasts that don't suck, 2014 edition"]]
+
+* [The Memory Palace](http://feeds.feedburner.com/thememorypalace):
+  This is the way history should be taught, but rarely is. Nate DiMeo
+  takes past events and puts you in the middle of them, in a way that
+  makes you emphathise so much with people from the past. Each episode
+  is a little short story, and they're often only a few minutes long.
+  A great example is this
+  [description of when Niagra falls stopped](http://traffic.libsyn.com/memorypalace/Rush_and_Roar.mp3).
+  I have listened to the entire back archive, and want *more*. Only downside
+  is it's a looong time between new episodes.
+* [The Haskell Cast](http://www.haskellcast.com/feed.xml): Panel
+  discussion with a guest, there is
+  a lot of expertise amoung them and I'm often scrambling to keep up with
+  the barrage of ideas. If this seems too tame, check out
+  [The Type Theory Podcast](http://typetheorypodcast.com/feed/podcast) instead..
+* [Benjamen Walker's Theory of Everything](http://toe.prx.org/feed/): Only
+  caught 2 episodes so far, but they've both been great. Short, punchy,
+  quirky, geeky. Astoundingly good production values.
+* [Lightspeed magazine](http://www.lightspeedmagazine.com/feed/) and
+  [Escape Pod](http://escapepod.org/feed/) blur together for me. Both
+  feature 20-50 minute science fiction short stories, and occasionally
+  other genre fictions. They seem to get all the award-winning short
+  stories. I sometimes fall asleep to these which can make
+  for strange dreams. Two strongly contrasting examples:
+  "[Observations About Eggs from the Man Sitting Next to Me on a Flight from Chicago, Illinois to Cedar Rapids, Iowa](http://www.podtrac.com/pts/redirect.mp3/www.lightspeedmagazine.com/podcasts/podcast_155-Observations_About_Eggs_from_etc-Carmen_Maria_Machado.mp3)"
+  and "[Pay Phobetor](http://www.podtrac.com/pts/redirect.mp3/www.lightspeedmagazine.com/podcasts/podcast_191-Pay_Phobetor-Shale_Nelson.mp3)"
+* [Serial](http://feeds.serialpodcast.org/serialpodcast): You probably
+  already know about this high profile TAL spinoff.
+  If you didn't before: You're welcome. :) Nuff said.
+* [Redecentralize](http://redecentralize.org/podcast/feed.rss): Interviews
+  with creatores of decentralized internet tools like Tahoe-LAFS, Ethereum,
+  Media Goblin, TeleHash. I just wish it went into more depth on protocols
+  and how they work.
+* [Love and Radio](http://feed.loveandradio.org/loveplusradio):
+  This American Life squared and on acid.
+* [Debian & Stuff](http://www.debianandstuff.com/listen/?format=rss):
+  My friend Asheesh and that guy I ate Thai food with once in Portland
+  in a marvelously unfocused podcast that somehow connects everything
+  up in the end. Only one episode so far; what are you guys waiting on? :P
+* [Hacker Public Radio](http://hackerpublicradio.org/hpr_ogg_rss.php):
+  Anyone can upload an episode, and multiple episodes are published each
+  week, which makes this a grab bag to pick and choose from occasionally.
+  While mostly about Linux and Free Software, the best episodes
+  are those that veer var afield, such as the 40 minute river swim
+  recording featured in [Wildswimming in France](http://hackerpublicradio.org/eps/hpr1528.ogg).
+
+Also, out of the podcasts I listed [[previously|podcasts_that_dont_suck]],
+I still listen to and enjoy Free As In Freedom, Off the Hook, and the Long Now
+Seminars.
+
+PS: A nice podcatcher, for the technically inclined is
+[git-annex importfeed](http://git-annex.branchable.com/tips/downloading_podcasts/).
+Featuring list of feeds in a text file, and distributed podcatching!
+
+[[!meta title="podcasts that dont suck 2014"]]

Added a comment: debirf?
diff --git a/blog/entry/clean_OS_reinstalls_with_propellor/comment_1_fd1f47d30d9a39df44fabb8c2b93a65c._comment b/blog/entry/clean_OS_reinstalls_with_propellor/comment_1_fd1f47d30d9a39df44fabb8c2b93a65c._comment
new file mode 100644
index 0000000..8677ff8
--- /dev/null
+++ b/blog/entry/clean_OS_reinstalls_with_propellor/comment_1_fd1f47d30d9a39df44fabb8c2b93a65c._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="https://id.koumbit.net/anarcat"
+ subject="debirf?"
+ date="2014-12-09T17:21:17Z"
+ content="""
+instead of reimplementing debian-live - could we interest you in using debirf? http://cmrg.fifthhorseman.net/wiki/debirf
+
+i've had good success in implementing initrd-based bootable filesystems (which is basically what d-i is) using it, and i can't imagine why propellor couldn't be added to a debirf image... 
+"""]]

video
diff --git a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
index 2b22e2e..9fcd34e 100644
--- a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
+++ b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
@@ -31,6 +31,8 @@ testvm = host "testvm.kitenet.net"
         & User.hasSomePassword "root"
 """]]
 
+And here's [a video of it in action](http://downloads.kitenet.net/videos/propellor_clean_OS_reinstall.ogv).
+
 ----
 
 It was surprisingly easy to build this. Propellor already knew how to

tweak
diff --git a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
index 4e6cfbf..2b22e2e 100644
--- a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
+++ b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
@@ -71,11 +71,12 @@ So, what gives? Why is this so much easier? There are a lot of reasons:
   calling underpowered busybox commands etc. Properties often Just Work
   the first time they're tested.
 
-* No separate runtime. d-i runs in its own environment. Propellor
-  drops into a live system and runs there. So I don't need to worry about
-  booting up the system, getting it on the network, etc etc. This probably
-  removes another order of magnitude of complexity from propellor as
-  compared with d-i.
+* No separate runtime. d-i runs in its own environment, which is really
+  a little custom linux distribution. Developing linux distributions is
+  hard. Propellor drops into a live system and runs there. So I don't need
+  to worry about booting up the system, getting it on the network, etc etc.
+  This probably removes another order of magnitude of complexity from
+  propellor as compared with d-i.
 
 This seems like the opposite of the Second System effect to me.
 So perhaps d-i was the second system all along?

indent
diff --git a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
index f025faf..4e6cfbf 100644
--- a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
+++ b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
@@ -28,7 +28,7 @@ testvm = host "testvm.kitenet.net"
         & Hostname.searchDomain
         & Apt.installed ["linux-image-amd64"]
         & Apt.installed ["ssh"]
-	& User.hasSomePassword "root"
+        & User.hasSomePassword "root"
 """]]
 
 ----

blog update
diff --git a/blog/entry/clean_OS_reinstalls_with_propellor.mdwn b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
new file mode 100644
index 0000000..f025faf
--- /dev/null
+++ b/blog/entry/clean_OS_reinstalls_with_propellor.mdwn
@@ -0,0 +1,105 @@
+You have a machine someplace, probably in The Cloud, and it has Linux
+installed, but not to your liking. You want to do a clean reinstall,
+maybe switching the distribution, or getting rid of the cruft. But
+this requires running an installer, and it's too difficult to run d-i on
+remote machines.
+
+Wouldn't it be nice if you could point a program at that machine and have
+it do a reinstall, on the fly, while the machine was running?
+
+This is what I've now taught propellor to do! Here's a working
+configuration which will make propellor convert a system running Fedora
+(or probably many other Linux distros) to Debian:
+
+[[!format haskell """
+testvm :: Host
+testvm = host "testvm.kitenet.net"
+        & os (System (Debian Unstable) "amd64")
+        & OS.cleanInstallOnce (OS.Confirmed "testvm.kitenet.net")
+                `onChange` propertyList "fixing up after clean install"
+                        [ User.shadowConfig True
+                        , OS.preserveRootSshAuthorized
+                        , OS.preserveResolvConf
+                        , Apt.update
+                        , Grub.boots "/dev/sda"
+                                `requires` Grub.installed Grub.PC
+                        ]
+        & Hostname.sane
+        & Hostname.searchDomain
+        & Apt.installed ["linux-image-amd64"]
+        & Apt.installed ["ssh"]
+	& User.hasSomePassword "root"
+"""]]
+
+----
+
+It was surprisingly easy to build this. Propellor already knew how to
+[[create a chroot|propelling_containers]], so from there it basically
+just has to move files around until the chroot takes over from the old OS.
+
+After the cleanInstallOnce property does its thing, propellor is running
+inside a freshly debootstrapped Debian system. Then we just need a few more
+Propertites to get from there to a bootable, usable system: Install grub
+and the kernel, turn on shadow passwords, preserve a few config files
+from the old OS, etc.
+
+It's really astounding to me how much easier this was to build than it
+was to build d-i. It took *years* to get d-i to the point of being able to
+install a working system. It took me a few part days to add this capability
+to propellor (It's 200 lines of code), and I've probably spent a total of
+less than 30 days total developing propellor in its entirity.
+
+So, what gives? Why is this so much easier? There are a lot of reasons:
+
+* Technology is so much better now. I can spin up cloud VMs for testing
+  in seconds; I use VirtualBox to restore a system from a snapshot. So
+  testing is much much easier. The first work on d-i was done by booting
+  real machines, and for a while I was booting them using *floppies*.
+
+* Propellor doesn't have a user interface. The best part of d-i is preseeding,
+  but that was mostly an accident; when I started developing d-i the first
+  thing I wrote was main-menu (which is invisible 99.9% of the time)
+  and we had to develop cdebconf, and tons of other UI. Probably 90% of
+  d-i work involves the UI. Jettisoning the UI entirely thus speeds up
+  development enormously. And propellor's configuration file blows d-i
+  preseeding out of the water in expressiveness and flexability.
+
+* Propellor has a much more principled design and implementation.
+  Separating things into Properties, which are composable and reusable
+  gives enormous leverage. Strong type checking and a powerful programming
+  language make it much easier to develop than d-i's mess of shell scripts
+  calling underpowered busybox commands etc. Properties often Just Work
+  the first time they're tested.
+
+* No separate runtime. d-i runs in its own environment. Propellor
+  drops into a live system and runs there. So I don't need to worry about
+  booting up the system, getting it on the network, etc etc. This probably
+  removes another order of magnitude of complexity from propellor as
+  compared with d-i.
+
+This seems like the opposite of the Second System effect to me.
+So perhaps d-i was the second system all along?
+
+I don't know if I'm going to take this all the way to
+[[propellor_is_d-i_2.0]]. But in theory, all that's needed now is:
+
+* Teaching propellor how to build a bootable image, containing a
+  live Debian system and propellor. (Yes, this would mean reimplementing
+  debian-live, but I estimate 100 lines of code to do it in propellor;
+  most of the Properties needed already exist.)
+  That image would then be booted up and perform the installation.
+* Some kind of UI that generates the propellor config file.
+* Adding Properties to partition the disk.
+
+----
+
+`cleanInstallOnce` and associated Properties will be included in
+propellor's upcoming 1.1.0 release, and are available in git now.
+
+Oh BTW, you could parameterize a few Properties by OS, and Propellor
+could be used to install not just Debian or Ubuntu, but whatever Linux
+distribution you want. Patches welcomed...
+
+[[!tag propellor]]
+
+[[!meta title="clean OS reinstalls with propellor"]]

add news item for github-backup 1.20141204
diff --git a/code/github-backup/news/version_1.20140721.mdwn b/code/github-backup/news/version_1.20140721.mdwn
deleted file mode 100644
index db35154..0000000
--- a/code/github-backup/news/version_1.20140721.mdwn
+++ /dev/null
@@ -1,3 +0,0 @@
-github-backup 1.20140721 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Fix typo in fix for url parsing. Closes: #[755261](http://bugs.debian.org/755261)"""]]
\ No newline at end of file
diff --git a/code/github-backup/news/version_1.20141204.mdwn b/code/github-backup/news/version_1.20141204.mdwn
new file mode 100644
index 0000000..4d9fef2
--- /dev/null
+++ b/code/github-backup/news/version_1.20141204.mdwn
@@ -0,0 +1,4 @@
+github-backup 1.20141204 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Fix broken argument parser for the username|organization parameter.
+     Closes: #[772043](http://bugs.debian.org/772043)"""]]
\ No newline at end of file

typo
diff --git a/blog/entry/snowdrift.mdwn b/blog/entry/snowdrift.mdwn
index deb704d..78c60ae 100644
--- a/blog/entry/snowdrift.mdwn
+++ b/blog/entry/snowdrift.mdwn
@@ -20,7 +20,7 @@ about, and seeing this button:
 <img src="https://snowdrift.coop/static/img/intro/pledge-button-draft.png"
 alt="1283 patrons will donate MORE when you pledge">
 
-That's a lot stronger incentive than some paypal dontation button or flattr
+That's a lot stronger incentive than some paypal donation button or flattr
 link! The details of how it works are explained on 
 [their intro page](https://snowdrift.coop/p/snowdrift/w/en/intro),
 or see the ever-insightful and thoughtful Mike Linksvayer's

blog update
diff --git a/blog/entry/snowdrift.mdwn b/blog/entry/snowdrift.mdwn
new file mode 100644
index 0000000..deb704d
--- /dev/null
+++ b/blog/entry/snowdrift.mdwn
@@ -0,0 +1,40 @@
+[[!meta title="snowdrift - sustainable crowdfunding for free software development"]]
+
+In a [recent blog post](blog/entry/continuing_to_be_pleasantly_surprised),
+I mentioned how lucky I feel to keep finding ways to work on free software.
+In the past couple years, I've had a successful Kickstarter, and followed
+that up with a second crowdfunding campaign, and now a grant is funding my
+work. A lot to be thankful for.
+
+A one-off crowdfunding campaign to fund free software development is
+wonderful, if you can pull it off. It can start a new project, or kick
+an existing one into a higher gear. But in many ways, free software
+development is a poor match for kickstarter-type crowdfunding. Especially
+when it comes to ongoing development, which it's really hard to do a
+crowdfunding pitch for. That's why I was excited to find
+[Snowdrift.coop](https://snowdrift.coop/), which has a unique approach.
+
+Imagine going to a web page for a free software project that you care
+about, and seeing this button:
+
+<img src="https://snowdrift.coop/static/img/intro/pledge-button-draft.png"
+alt="1283 patrons will donate MORE when you pledge">
+
+That's a lot stronger incentive than some paypal dontation button or flattr
+link! The details of how it works are explained on 
+[their intro page](https://snowdrift.coop/p/snowdrift/w/en/intro),
+or see the ever-insightful and thoughtful Mike Linksvayer's
+[blog post about it](http://gondwanaland.com/mlog/2014/11/30/snowdrift/).
+
+When I found out about this, I immediately sent them a one-off donation.
+Later, I got to meet one of the developers face to face in Portland.
+I've also done a small amount of work on the Snowdrift platform,
+which is itself free software. (My haskell code will actually render
+that button above!)
+
+Free software is important, and its funding should be based, not on how
+lucky or good we are at kickstarter pitches, but on its quality and how
+useful it is to everyone. Snowdrift is the most interesting thing I've seen
+in this space, and I really hope they succeed. If you agree, they're
+[running their own crowdfunding campaign right now](https://snowdrift.tilt.com/launch-snowdrift-coop).
+

add news item for moreutils 0.54
diff --git a/code/moreutils/news/version_0.48.mdwn b/code/moreutils/news/version_0.48.mdwn
deleted file mode 100644
index cb1ab02..0000000
--- a/code/moreutils/news/version_0.48.mdwn
+++ /dev/null
@@ -1,10 +0,0 @@
-moreutils 0.48 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Allow overriding PREFIX and CFLAGS to make the build more flexible
-     (Thanks, Ben Walton)
-   * Typo. Closes: #[697113](http://bugs.debian.org/697113)
-   * ts: -i enables incremental timestamping.
-     Thanks, Thomas Vander Stichele
-   * ts: Support single-digit day dates.
-     Thanks, Peter Lunicks
-   * sponge: Check fclose to detect certian short reads. Closes: #[704453](http://bugs.debian.org/704453)"""]]
\ No newline at end of file
diff --git a/code/moreutils/news/version_0.54.mdwn b/code/moreutils/news/version_0.54.mdwn
new file mode 100644
index 0000000..fd13712
--- /dev/null
+++ b/code/moreutils/news/version_0.54.mdwn
@@ -0,0 +1,5 @@
+moreutils 0.54 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * vidir: Fix bug in handling filenames that share a common
+     prefix when renaming. Closes: #[654326](http://bugs.debian.org/654326)
+     Thanks, Kushal Kumaran"""]]
\ No newline at end of file

add flier
diff --git a/learnstofly.mdwn b/learnstofly.mdwn
index c2fc1c9..bd36fbb 100644
--- a/learnstofly.mdwn
+++ b/learnstofly.mdwn
@@ -34,4 +34,4 @@ Supported by The Kentucky Educational Telvision Fund for Independent Production
 If you can't see the video above, [[download_it|joey_learns_to_fly.ogg]].
 
 Copyright 1992 Ed Counts, made available for personal use 
-only. [[flying.png]]
+only. <a href="flyer.jpg">[[flying.png]]</a>
diff --git a/learnstofly/flyer.jpg b/learnstofly/flyer.jpg
new file mode 100644
index 0000000..2dac875
Binary files /dev/null and b/learnstofly/flyer.jpg differ

diff --git a/code/etckeeper/discussion.mdwn b/code/etckeeper/discussion.mdwn
index 3222ee6..e1d111f 100644
--- a/code/etckeeper/discussion.mdwn
+++ b/code/etckeeper/discussion.mdwn
@@ -241,5 +241,6 @@ It'd be great if the automatic commits generated by the package manager could in
 
 I looked at the post-invoke hook that etckeeper puts in /etc/apt/apt.conf.d, but it wasn't clear to me if there was an easy way to get the apt-get command line that was run directly.  But I thought maybe one could scrape that out of the logs, if apt-get writes the /var/log/apt/history.log entry before it calls the post-invoke hooks?  I realize there might be a bit of a race condition there with multiple executions of apt-get, but it seems like it'd usually work pretty well.  --Nick
 
+---
 
-
+There is some odd behavior when doing a rebase with a reword. The .etckeeper file gets conflicts (could be because of http://git.661346.n2.nabble.com/rebase-i-reword-runs-pre-commit-hook-with-curious-results-td7244648.html). This is easy to work-around with a manual `etckeeper pre-commit` before `git rebase --continue` but I wonder if the pre-commit hook can be modified to make this work seamlessly?

typo
diff --git a/blog/entry/propelling_containers.mdwn b/blog/entry/propelling_containers.mdwn
index f3ea580..0399a90 100644
--- a/blog/entry/propelling_containers.mdwn
+++ b/blog/entry/propelling_containers.mdwn
@@ -83,7 +83,7 @@ example = host "mylaptop"
 	& Chroot.provisioned (buildDepChroot "git-annex")
 
 buildDepChroot :: Apt.Package -> Chroot.Chroot
-buildDepChroot pkg = Chroot.debootstrapped system Debootstrap.buildd dir
+buildDepChroot pkg = Chroot.debootstrapped system Debootstrap.BuildD dir
 	& Apt.buildDep pkg
   where
 	dir = /srv/chroot/builddep/"++pkg

Added a comment
diff --git a/blog/entry/a_programmable_alarm_clock_using_systemd/comment_9_4a88a65fc9f1b607323779e18ede544d._comment b/blog/entry/a_programmable_alarm_clock_using_systemd/comment_9_4a88a65fc9f1b607323779e18ede544d._comment
new file mode 100644
index 0000000..a7d6fad
--- /dev/null
+++ b/blog/entry/a_programmable_alarm_clock_using_systemd/comment_9_4a88a65fc9f1b607323779e18ede544d._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawmAf-ieEypOj0tLTIEE3tEJe2F939erllY"
+ nickname="Ivan"
+ subject="comment 9"
+ date="2014-11-22T09:23:22Z"
+ content="""
+> Heya! Unfortunately this wouldn't work as a per-user unit btw, as WakeSystem= timers require privileges.
+
+Strange, I've got a similar setup (without inhibition, though) working flawlessly as a per-user unit. Arch, systemd 217, all defaults (no special configuration of privileges took place).
+"""]]

removed
diff --git a/blog/entry/a_programmable_alarm_clock_using_systemd/comment_11_e85a77418ab6ce01939799f2af20f5ef._comment b/blog/entry/a_programmable_alarm_clock_using_systemd/comment_11_e85a77418ab6ce01939799f2af20f5ef._comment
deleted file mode 100644
index 0b9a31f..0000000
--- a/blog/entry/a_programmable_alarm_clock_using_systemd/comment_11_e85a77418ab6ce01939799f2af20f5ef._comment
+++ /dev/null
@@ -1,9 +0,0 @@
-[[!comment format=mdwn
- username="https://www.google.com/accounts/o8/id?id=AItOawmAf-ieEypOj0tLTIEE3tEJe2F939erllY"
- nickname="Ivan"
- subject="comment 11"
- date="2014-11-22T09:21:02Z"
- content="""
-> Heya! Unfortunately this wouldn't work as a per-user unit btw, as WakeSystem= timers require privileges.
-Strange, I've got a similar setup (without inhibition, though) which works flawlessly as a per-user unit. Arch, systemd 217, all defaults.
-"""]]

removed
diff --git a/blog/entry/a_programmable_alarm_clock_using_systemd/comment_9_64abd8a595f1b8ffeb788fa1c8078bff._comment b/blog/entry/a_programmable_alarm_clock_using_systemd/comment_9_64abd8a595f1b8ffeb788fa1c8078bff._comment
deleted file mode 100644
index 9b37235..0000000
--- a/blog/entry/a_programmable_alarm_clock_using_systemd/comment_9_64abd8a595f1b8ffeb788fa1c8078bff._comment
+++ /dev/null
@@ -1,9 +0,0 @@
-[[!comment format=mdwn
- username="https://www.google.com/accounts/o8/id?id=AItOawmAf-ieEypOj0tLTIEE3tEJe2F939erllY"
- nickname="Ivan"
- subject="comment 9"
- date="2014-11-22T09:18:05Z"
- content="""
-> Heya! Unfortunately this wouldn't work as a per-user unit btw, as WakeSystem= timers require privileges.
-Strange, I've got a similar setup (without inhibition, though) which works flawlessly as a per-user unit. Arch, systemd 217, all defaults.
-"""]]

removed
diff --git a/blog/entry/a_programmable_alarm_clock_using_systemd/comment_10_0340f8604bbac5ce622bf69be08ff6f0._comment b/blog/entry/a_programmable_alarm_clock_using_systemd/comment_10_0340f8604bbac5ce622bf69be08ff6f0._comment
deleted file mode 100644
index 75f74c1..0000000
--- a/blog/entry/a_programmable_alarm_clock_using_systemd/comment_10_0340f8604bbac5ce622bf69be08ff6f0._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="https://www.google.com/accounts/o8/id?id=AItOawmAf-ieEypOj0tLTIEE3tEJe2F939erllY"
- nickname="Ivan"
- subject="comment 10"
- date="2014-11-22T09:19:58Z"
- content="""
-> Heya! Unfortunately this wouldn't work as a per-user unit btw, as WakeSystem= timers require privileges.
-
-Strange, I've got a similar setup (without inhibition, though) which works flawlessly as a per-user unit. Arch, systemd 217, all defaults.
-"""]]