Recent changes to this wiki:

calendar update
diff --git a/archives/2024.mdwn b/archives/2024.mdwn
new file mode 100644
index 0000000..a3c0cdb
--- /dev/null
+++ b/archives/2024.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2024 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2024/01.mdwn b/archives/2024/01.mdwn
new file mode 100644
index 0000000..eabfb74
--- /dev/null
+++ b/archives/2024/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/02.mdwn b/archives/2024/02.mdwn
new file mode 100644
index 0000000..521c690
--- /dev/null
+++ b/archives/2024/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/03.mdwn b/archives/2024/03.mdwn
new file mode 100644
index 0000000..023d9e7
--- /dev/null
+++ b/archives/2024/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/04.mdwn b/archives/2024/04.mdwn
new file mode 100644
index 0000000..89ac372
--- /dev/null
+++ b/archives/2024/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/05.mdwn b/archives/2024/05.mdwn
new file mode 100644
index 0000000..82fa0bc
--- /dev/null
+++ b/archives/2024/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/06.mdwn b/archives/2024/06.mdwn
new file mode 100644
index 0000000..2f0d34a
--- /dev/null
+++ b/archives/2024/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/07.mdwn b/archives/2024/07.mdwn
new file mode 100644
index 0000000..e40a494
--- /dev/null
+++ b/archives/2024/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/08.mdwn b/archives/2024/08.mdwn
new file mode 100644
index 0000000..d59e39f
--- /dev/null
+++ b/archives/2024/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/09.mdwn b/archives/2024/09.mdwn
new file mode 100644
index 0000000..0231a47
--- /dev/null
+++ b/archives/2024/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/10.mdwn b/archives/2024/10.mdwn
new file mode 100644
index 0000000..2b17404
--- /dev/null
+++ b/archives/2024/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/11.mdwn b/archives/2024/11.mdwn
new file mode 100644
index 0000000..a1beafa
--- /dev/null
+++ b/archives/2024/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2024/12.mdwn b/archives/2024/12.mdwn
new file mode 100644
index 0000000..65adbba
--- /dev/null
+++ b/archives/2024/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2024 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2024) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

calendar update
diff --git a/archives/2023.mdwn b/archives/2023.mdwn
new file mode 100644
index 0000000..cd03157
--- /dev/null
+++ b/archives/2023.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2023 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2023/01.mdwn b/archives/2023/01.mdwn
new file mode 100644
index 0000000..c2ed2a1
--- /dev/null
+++ b/archives/2023/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/02.mdwn b/archives/2023/02.mdwn
new file mode 100644
index 0000000..428672c
--- /dev/null
+++ b/archives/2023/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/03.mdwn b/archives/2023/03.mdwn
new file mode 100644
index 0000000..3286b48
--- /dev/null
+++ b/archives/2023/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/04.mdwn b/archives/2023/04.mdwn
new file mode 100644
index 0000000..4a82af2
--- /dev/null
+++ b/archives/2023/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/05.mdwn b/archives/2023/05.mdwn
new file mode 100644
index 0000000..51b064e
--- /dev/null
+++ b/archives/2023/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/06.mdwn b/archives/2023/06.mdwn
new file mode 100644
index 0000000..7454b86
--- /dev/null
+++ b/archives/2023/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/07.mdwn b/archives/2023/07.mdwn
new file mode 100644
index 0000000..ff45784
--- /dev/null
+++ b/archives/2023/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/08.mdwn b/archives/2023/08.mdwn
new file mode 100644
index 0000000..a4ac30d
--- /dev/null
+++ b/archives/2023/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/09.mdwn b/archives/2023/09.mdwn
new file mode 100644
index 0000000..b58593a
--- /dev/null
+++ b/archives/2023/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/10.mdwn b/archives/2023/10.mdwn
new file mode 100644
index 0000000..2a342da
--- /dev/null
+++ b/archives/2023/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/11.mdwn b/archives/2023/11.mdwn
new file mode 100644
index 0000000..7c1a244
--- /dev/null
+++ b/archives/2023/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2023/12.mdwn b/archives/2023/12.mdwn
new file mode 100644
index 0000000..66d5788
--- /dev/null
+++ b/archives/2023/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2023 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2023) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

calendar update
diff --git a/archives/2022.mdwn b/archives/2022.mdwn
new file mode 100644
index 0000000..e738afc
--- /dev/null
+++ b/archives/2022.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2022 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2022/01.mdwn b/archives/2022/01.mdwn
new file mode 100644
index 0000000..b3ff765
--- /dev/null
+++ b/archives/2022/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/02.mdwn b/archives/2022/02.mdwn
new file mode 100644
index 0000000..9e109ab
--- /dev/null
+++ b/archives/2022/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/03.mdwn b/archives/2022/03.mdwn
new file mode 100644
index 0000000..4ff2fa6
--- /dev/null
+++ b/archives/2022/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/04.mdwn b/archives/2022/04.mdwn
new file mode 100644
index 0000000..04cada7
--- /dev/null
+++ b/archives/2022/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/05.mdwn b/archives/2022/05.mdwn
new file mode 100644
index 0000000..7a02820
--- /dev/null
+++ b/archives/2022/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/06.mdwn b/archives/2022/06.mdwn
new file mode 100644
index 0000000..0c2ff58
--- /dev/null
+++ b/archives/2022/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/07.mdwn b/archives/2022/07.mdwn
new file mode 100644
index 0000000..098c5b8
--- /dev/null
+++ b/archives/2022/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/08.mdwn b/archives/2022/08.mdwn
new file mode 100644
index 0000000..2151608
--- /dev/null
+++ b/archives/2022/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/09.mdwn b/archives/2022/09.mdwn
new file mode 100644
index 0000000..2f250b3
--- /dev/null
+++ b/archives/2022/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/10.mdwn b/archives/2022/10.mdwn
new file mode 100644
index 0000000..3584fc0
--- /dev/null
+++ b/archives/2022/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/11.mdwn b/archives/2022/11.mdwn
new file mode 100644
index 0000000..f883931
--- /dev/null
+++ b/archives/2022/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2022/12.mdwn b/archives/2022/12.mdwn
new file mode 100644
index 0000000..7d49307
--- /dev/null
+++ b/archives/2022/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2022 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2022) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

calendar update
diff --git a/archives/2021.mdwn b/archives/2021.mdwn
new file mode 100644
index 0000000..325ac2d
--- /dev/null
+++ b/archives/2021.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2021 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2021/01.mdwn b/archives/2021/01.mdwn
new file mode 100644
index 0000000..9b5bb5d
--- /dev/null
+++ b/archives/2021/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/02.mdwn b/archives/2021/02.mdwn
new file mode 100644
index 0000000..3903fe8
--- /dev/null
+++ b/archives/2021/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/03.mdwn b/archives/2021/03.mdwn
new file mode 100644
index 0000000..0c7f1e7
--- /dev/null
+++ b/archives/2021/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/04.mdwn b/archives/2021/04.mdwn
new file mode 100644
index 0000000..5fb95cb
--- /dev/null
+++ b/archives/2021/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/05.mdwn b/archives/2021/05.mdwn
new file mode 100644
index 0000000..ec47bca
--- /dev/null
+++ b/archives/2021/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/06.mdwn b/archives/2021/06.mdwn
new file mode 100644
index 0000000..8af1077
--- /dev/null
+++ b/archives/2021/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/07.mdwn b/archives/2021/07.mdwn
new file mode 100644
index 0000000..54ccb3d
--- /dev/null
+++ b/archives/2021/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/08.mdwn b/archives/2021/08.mdwn
new file mode 100644
index 0000000..d6242ff
--- /dev/null
+++ b/archives/2021/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/09.mdwn b/archives/2021/09.mdwn
new file mode 100644
index 0000000..a8d92cb
--- /dev/null
+++ b/archives/2021/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/10.mdwn b/archives/2021/10.mdwn
new file mode 100644
index 0000000..2514206
--- /dev/null
+++ b/archives/2021/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/11.mdwn b/archives/2021/11.mdwn
new file mode 100644
index 0000000..9c5f9fd
--- /dev/null
+++ b/archives/2021/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2021/12.mdwn b/archives/2021/12.mdwn
new file mode 100644
index 0000000..4132294
--- /dev/null
+++ b/archives/2021/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2021 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2021) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

calendar update
diff --git a/archives/2020.mdwn b/archives/2020.mdwn
new file mode 100644
index 0000000..8843a09
--- /dev/null
+++ b/archives/2020.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2020 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2020/01.mdwn b/archives/2020/01.mdwn
new file mode 100644
index 0000000..0577516
--- /dev/null
+++ b/archives/2020/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/02.mdwn b/archives/2020/02.mdwn
new file mode 100644
index 0000000..189d77c
--- /dev/null
+++ b/archives/2020/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/03.mdwn b/archives/2020/03.mdwn
new file mode 100644
index 0000000..63a191c
--- /dev/null
+++ b/archives/2020/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/04.mdwn b/archives/2020/04.mdwn
new file mode 100644
index 0000000..d8be67f
--- /dev/null
+++ b/archives/2020/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/05.mdwn b/archives/2020/05.mdwn
new file mode 100644
index 0000000..92e59fa
--- /dev/null
+++ b/archives/2020/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/06.mdwn b/archives/2020/06.mdwn
new file mode 100644
index 0000000..fff6e79
--- /dev/null
+++ b/archives/2020/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/07.mdwn b/archives/2020/07.mdwn
new file mode 100644
index 0000000..9674bf2
--- /dev/null
+++ b/archives/2020/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/08.mdwn b/archives/2020/08.mdwn
new file mode 100644
index 0000000..19eec13
--- /dev/null
+++ b/archives/2020/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/09.mdwn b/archives/2020/09.mdwn
new file mode 100644
index 0000000..282af8d
--- /dev/null
+++ b/archives/2020/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/10.mdwn b/archives/2020/10.mdwn
new file mode 100644
index 0000000..e459232
--- /dev/null
+++ b/archives/2020/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/11.mdwn b/archives/2020/11.mdwn
new file mode 100644
index 0000000..b462704
--- /dev/null
+++ b/archives/2020/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/12.mdwn b/archives/2020/12.mdwn
new file mode 100644
index 0000000..2503185
--- /dev/null
+++ b/archives/2020/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

calendar update
diff --git a/archives/2019.mdwn b/archives/2019.mdwn
new file mode 100644
index 0000000..ccc1c91
--- /dev/null
+++ b/archives/2019.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2019 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2019/01.mdwn b/archives/2019/01.mdwn
new file mode 100644
index 0000000..56a59b0
--- /dev/null
+++ b/archives/2019/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/02.mdwn b/archives/2019/02.mdwn
new file mode 100644
index 0000000..72dbd17
--- /dev/null
+++ b/archives/2019/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/03.mdwn b/archives/2019/03.mdwn
new file mode 100644
index 0000000..534ad69
--- /dev/null
+++ b/archives/2019/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/04.mdwn b/archives/2019/04.mdwn
new file mode 100644
index 0000000..b2a8a7e
--- /dev/null
+++ b/archives/2019/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/05.mdwn b/archives/2019/05.mdwn
new file mode 100644
index 0000000..53f5953
--- /dev/null
+++ b/archives/2019/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/06.mdwn b/archives/2019/06.mdwn
new file mode 100644
index 0000000..060e3e3
--- /dev/null
+++ b/archives/2019/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/07.mdwn b/archives/2019/07.mdwn
new file mode 100644
index 0000000..ea6d5c5
--- /dev/null
+++ b/archives/2019/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/08.mdwn b/archives/2019/08.mdwn
new file mode 100644
index 0000000..aba5c11
--- /dev/null
+++ b/archives/2019/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/09.mdwn b/archives/2019/09.mdwn
new file mode 100644
index 0000000..664ffb5
--- /dev/null
+++ b/archives/2019/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/10.mdwn b/archives/2019/10.mdwn
new file mode 100644
index 0000000..020dc4a
--- /dev/null
+++ b/archives/2019/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/11.mdwn b/archives/2019/11.mdwn
new file mode 100644
index 0000000..86c621a
--- /dev/null
+++ b/archives/2019/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2019/12.mdwn b/archives/2019/12.mdwn
new file mode 100644
index 0000000..46c9d95
--- /dev/null
+++ b/archives/2019/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2019 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2019) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

publishing
diff --git a/queue/20180515-on-hold.mdwn b/queue/20180515-on-hold.mdwn
deleted file mode 100644
index ee5d5c8..0000000
--- a/queue/20180515-on-hold.mdwn
+++ /dev/null
@@ -1,17 +0,0 @@
-[[!meta title="Yakking is on hold for now"]]
-[[!meta author="The Yakking Staff"]]
-[[!tag announcement meta]]
-
-After 242 articles and almost five years of almost weekly posts,
-we've run out of steam. Yakking is going to take an indefinite
-vacation. There will be no new articles, at least for now.
-
-We might start again later. There might be occasional articles at
-irregular intervals, if we feel energetic. Or not.
-
-We've enjoyed writing Yakking. We hope you've enjoyed reading Yakking.
-The site will remain, and the archives are still there for reading.
-
-Happy hacking. May the farce be with you. Be well.
-
-Daniel, Richard, and Lars.

Queue on-hold article
diff --git a/drafts/liw-on-hold.mdwn b/queue/20180515-on-hold.mdwn
similarity index 100%
rename from drafts/liw-on-hold.mdwn
rename to queue/20180515-on-hold.mdwn

Fix: typo
diff --git a/drafts/liw-on-hold.mdwn b/drafts/liw-on-hold.mdwn
index fd979ac..ee5d5c8 100644
--- a/drafts/liw-on-hold.mdwn
+++ b/drafts/liw-on-hold.mdwn
@@ -4,7 +4,7 @@
 
 After 242 articles and almost five years of almost weekly posts,
 we've run out of steam. Yakking is going to take an indefinite
-vacation. There will be no new articlea, at least for now.
+vacation. There will be no new articles, at least for now.
 
 We might start again later. There might be occasional articles at
 irregular intervals, if we feel energetic. Or not.

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

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

Add: draft of on-hold announcement
diff --git a/drafts/liw-on-hold.mdwn b/drafts/liw-on-hold.mdwn
new file mode 100644
index 0000000..fd979ac
--- /dev/null
+++ b/drafts/liw-on-hold.mdwn
@@ -0,0 +1,17 @@
+[[!meta title="Yakking is on hold for now"]]
+[[!meta author="The Yakking Staff"]]
+[[!tag announcement meta]]
+
+After 242 articles and almost five years of almost weekly posts,
+we've run out of steam. Yakking is going to take an indefinite
+vacation. There will be no new articlea, at least for now.
+
+We might start again later. There might be occasional articles at
+irregular intervals, if we feel energetic. Or not.
+
+We've enjoyed writing Yakking. We hope you've enjoyed reading Yakking.
+The site will remain, and the archives are still there for reading.
+
+Happy hacking. May the farce be with you. Be well.
+
+Daniel, Richard, and Lars.

publishing
diff --git a/queue/20180411-launcher-scripts.mdwn b/queue/20180411-launcher-scripts.mdwn
deleted file mode 100644
index aa42a26..0000000
--- a/queue/20180411-launcher-scripts.mdwn
+++ /dev/null
@@ -1,64 +0,0 @@
-[[!meta title="Writing launcher scripts"]]
-[[!meta author="Richard Maw"]]
-[[!tag shell]]
-
-Unless your program is compiled into one big binary lump
-it will typically need to load other assets on program start.
-
-This is usually libraries, though other assets may also be required.
-
-Your programming environment will define some standard locations
-(see [hier(7)][] for some examples),
-but will normally have a way to specify more.
-
-*   C programs will look for libraries in directories listed
-    as : separated strings in the `LD_LIBRARY_PATH` environment variable.
-*   Python programs will look in `PYTHONPATH`.
-*   Lua programs will look in `LUA_PATH`, `LUA_CPATH`
-    and other environment variables
-    based on the version of the Lua interpreter.
-*   Java will look in its class path,
-    which can be set with the `-classpath` option.
-*   Executables will be sought in the `PATH` environment variable.
-
-If you only need assets in the standard locations
-then you wouldn't normally need to change anything.
-
-However you're not always able to stick to only distribution provided software.
-
-In this case you need to use software which has "bundled" its dependencies
-alongside its own software.
-
-Linux ELF binaries can make use of its "RPATH" to add extra paths,
-but most executable formats don't have a direct equivalent.
-
-In which case we can instead specify the new locations with a wrapper script.
-The standard trick is to use `$0` for the name of the script,
-[dirname(1)][] to get the directory the script is located in,
-and [readlink(1)][] `-f` on the to turn it into an absolute path.
-
-[[!format sh """
-#!/bin/sh
-D="$(dirname "$(readlink -f "$0")")"
-cp="$(set -- "$D/support/jars/"*.jar; IFS=:; printf %s "$*")"
-exec java -classpath "$cp" com.myapplication.Main "$@"
-"""]]
-
-This works for running the script in the directory the assets are stored in,
-but it can be convenient to add the program to a directory in `PATH`.
-
-If written as a bash script you can use `$BASH_SOURCE`
-which is guaranteed to be the path of the script,
-and in circumstances I can now no longer reproduce
-I needed to use it instead of `$0`.
-
-[[!format sh """
-#!/bin/bash
-D="$(dirname "$(readlink -f "${BASH_SOURCE}")")"
-cp="$(set -- "$D/support/jars/"*.jar; IFS=:; printf %s "$*")"
-exec java -classpath "$cp" com.myapplication.Main "$@"
-"""]]
-
-[hier(7)]: https://linux.die.net/man/7/hier
-[dirname(1)]: http://man7.org/linux/man-pages/man1/dirname.1.html
-[readlink(1)]: http://man7.org/linux/man-pages/man1/readlink.1.html

enqueue article
diff --git a/drafts/skullman-launcher-scripts.mdwn b/queue/20180411-launcher-scripts.mdwn
similarity index 100%
rename from drafts/skullman-launcher-scripts.mdwn
rename to queue/20180411-launcher-scripts.mdwn

standardise on assets on the name of dependencies
diff --git a/drafts/skullman-launcher-scripts.mdwn b/drafts/skullman-launcher-scripts.mdwn
index 9ad3b23..aa42a26 100644
--- a/drafts/skullman-launcher-scripts.mdwn
+++ b/drafts/skullman-launcher-scripts.mdwn
@@ -3,7 +3,7 @@
 [[!tag shell]]
 
 Unless your program is compiled into one big binary lump
-it will typically need to load other resources on program start.
+it will typically need to load other assets on program start.
 
 This is usually libraries, though other assets may also be required.
 
@@ -21,7 +21,7 @@ but will normally have a way to specify more.
     which can be set with the `-classpath` option.
 *   Executables will be sought in the `PATH` environment variable.
 
-If you only need resources in the standard locations
+If you only need assets in the standard locations
 then you wouldn't normally need to change anything.
 
 However you're not always able to stick to only distribution provided software.

Add rambling about launcher scripts
diff --git a/drafts/skullman-launcher-scripts.mdwn b/drafts/skullman-launcher-scripts.mdwn
new file mode 100644
index 0000000..9ad3b23
--- /dev/null
+++ b/drafts/skullman-launcher-scripts.mdwn
@@ -0,0 +1,64 @@
+[[!meta title="Writing launcher scripts"]]
+[[!meta author="Richard Maw"]]
+[[!tag shell]]
+
+Unless your program is compiled into one big binary lump
+it will typically need to load other resources on program start.
+
+This is usually libraries, though other assets may also be required.
+
+Your programming environment will define some standard locations
+(see [hier(7)][] for some examples),
+but will normally have a way to specify more.
+
+*   C programs will look for libraries in directories listed
+    as : separated strings in the `LD_LIBRARY_PATH` environment variable.
+*   Python programs will look in `PYTHONPATH`.
+*   Lua programs will look in `LUA_PATH`, `LUA_CPATH`
+    and other environment variables
+    based on the version of the Lua interpreter.
+*   Java will look in its class path,
+    which can be set with the `-classpath` option.
+*   Executables will be sought in the `PATH` environment variable.
+
+If you only need resources in the standard locations
+then you wouldn't normally need to change anything.
+
+However you're not always able to stick to only distribution provided software.
+
+In this case you need to use software which has "bundled" its dependencies
+alongside its own software.
+
+Linux ELF binaries can make use of its "RPATH" to add extra paths,
+but most executable formats don't have a direct equivalent.
+
+In which case we can instead specify the new locations with a wrapper script.
+The standard trick is to use `$0` for the name of the script,
+[dirname(1)][] to get the directory the script is located in,
+and [readlink(1)][] `-f` on the to turn it into an absolute path.
+
+[[!format sh """
+#!/bin/sh
+D="$(dirname "$(readlink -f "$0")")"
+cp="$(set -- "$D/support/jars/"*.jar; IFS=:; printf %s "$*")"
+exec java -classpath "$cp" com.myapplication.Main "$@"
+"""]]
+
+This works for running the script in the directory the assets are stored in,
+but it can be convenient to add the program to a directory in `PATH`.
+
+If written as a bash script you can use `$BASH_SOURCE`
+which is guaranteed to be the path of the script,
+and in circumstances I can now no longer reproduce
+I needed to use it instead of `$0`.
+
+[[!format sh """
+#!/bin/bash
+D="$(dirname "$(readlink -f "${BASH_SOURCE}")")"
+cp="$(set -- "$D/support/jars/"*.jar; IFS=:; printf %s "$*")"
+exec java -classpath "$cp" com.myapplication.Main "$@"
+"""]]
+
+[hier(7)]: https://linux.die.net/man/7/hier
+[dirname(1)]: http://man7.org/linux/man-pages/man1/dirname.1.html
+[readlink(1)]: http://man7.org/linux/man-pages/man1/readlink.1.html

publishing
diff --git a/queue/20180404-text-to-speech.mdwn b/queue/20180404-text-to-speech.mdwn
deleted file mode 100644
index 968b2e8..0000000
--- a/queue/20180404-text-to-speech.mdwn
+++ /dev/null
@@ -1,146 +0,0 @@
-[[!meta title="Text To Speech"]]
-[[!meta author="Richard Maw"]]
-[[!tag pulseaudio festival text-to-speech shell]]
-
-What do you do if you need to be present on a call but you've lost your voice?
-Why write an 11 line shell script to replace it of course!
-
-Our first port of call is of course to Google!
-So what is the first result for "linux text to speech"?
-(well for me it's [RPi Text to Speech (Speech Synthesis)][])
-and deep down there after Cepstral it's) Festival of course!
-
-So how do we use that?
-
-First we need to install it. Since I wrote this on an Ubuntu system I do:
-
-[[!format sh """
-$ apt install festival
-"""]]
-
-This installs the `festival` command,
-which has a convenient `--tts` option!
-
-[[!format sh """
-$ echo hello world | festival --tts
-"""]]
-
-This however has two problems:
-
-1.  It is fatiguing on the fingers to tweak the parameters and run the command.
-2.  The output of the command is to the speakers rather than a microphone.
-
-We can fix problem 1 with a trivial shell script
-to produce output after every line instead.
-
-[[!format sh """
-#!/bin/sh
-while read -r REPLY; do
-        printf %s "$REPLY" | festival --tts
-done
-"""]]
-
-The problem of outputting to a microphone is somewhat more involved.
-
-It's possible to loop your speaker output through a recording device
-in Pulse Audio by setting the recording device to a "Monitor" device.
-
-It's no doubt possible to drive this from the command-line,
-but since my chat software is graphical I've no problem using `pavucontrol`.
-
-Once the chat software is running the "Recording" tab
-and change the input device of the application.
-
-This works but is unsatisfying because you need a second output device
-otherwise other sounds will be broadcast
-and is prone to causing feedback.
-
-What we need is some kind of virtual microphone.
-As usual, the likes of Google and StackOverflow come to hand,
-and a virtual microphone is what Pulse Audio calls a "null sink".
-
-We can create a null sink and give it a recognisable name by running:
-
-[[!format sh """
-pacmd load-module module-null-sink sink_name=Festival
-pacmd update-sink-proplist Festival device.description=Festival
-"""]]
-
-Then we can remove it again by running:
-
-[[!format sh """
-pacmd unload-module module-null-sink
-"""]]
-
-So how do we get festival to play its output to that?
-
-We can't start the command, then tweak the parameters in `pavucontrol`
-because it doesn't run long enough to change that before it starts playing.
-
-We can play audio to a specified device with the `paplay` command,
-but how do we get Festival to output?
-
-Fortunately Festival lets you set some parameters in its scripting language.
-
-We need to pick a common audio format that `paplay` can read
-and `festival` can produce.
-We can set this with:
-
-[[!format lisp """
-(Parameter.set 'Audio_Required_Format 'aiff)
-"""]]
-
-We need to tell festival to play audio through a specified Pulse Audio device.
-The best way I could find to do this
-was setting `Audio_Method` to `Audio_Command`
-and `Audio_Command` to a `paplay` command.
-
-[[!format lisp """
-(Parameter.set 'Audio_Method 'Audio_Command)
-(Parameter.set 'Audio_Command "paplay $FILE --client-name=Festival --stream-name=Speech --device=Festival")
-"""]]
-
-Festival lets us run commands on its command-line so the final script we get is:
-
-[[!format sh """
-#!/bin/sh
-pacmd load-module module-null-sink sink_name=Festival
-pacmd update-sink-proplist Festival device.description=Festival
-while read -r REPLY; do
-        festival --batch \
-                '(Parameter.set '\''Audio_Required_Format '\''aiff)' \
-                '(Parameter.set '\''Audio_Method '\''Audio_Command)' \
-                '(Parameter.set '\''Audio_Command "paplay $FILE --client-name=Festival --stream-name=Speech --device=Festival")' \
-                '(SayText "'"$REPLY"'")'
-done
-pacmd unload-module module-null-sink
-"""]]
-
-1.  Run that in a terminal window.
-2.  Start your chat program.
-3.  Start `pavucontrol` and change the input device of your program to Festival.
-4.  Type lines of text into the terminal to speak.
-
----
-
-Since this was a project to achieve the goal of being able to participate
-in a group chat without being able to speak, development stopped there.
-
-Should further development be warranted other changes could include:
-
-1.  The module load and unload process is pretty fragile.
-    Would need to use an API that is tied to process lifetime
-    or at least unload by ID rather than name.
-2.  No escaping mechanism for `$REPLY`.
-    Would need to learn string escaping in lisp.
-3.  Lots of work done per line of text.
-    Festival has a server mode which could reduce the amount of work per line.
-4.  Investigate a way to pipe audio directly between Festival and Pulse Audio.
-    `text2wave` exists to write to a file, possibly standard output,
-    and `pacat` exists to take audio from standard input and put it to speakers,
-    but I couldn't get it to work at the time.
-5.  Replace festival entirely.
-    It is in need of maintainership, and has been broken in Fedora releases,
-    so replacing the voice generation with pyttsx, espeak or flite could help.
-
-[RPi Text to Speech (Speech Synthesis)]: https://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis)

enqueue
diff --git a/drafts/skullman-text-to-speech.mdwn b/queue/20180404-text-to-speech.mdwn
similarity index 100%
rename from drafts/skullman-text-to-speech.mdwn
rename to queue/20180404-text-to-speech.mdwn

Mention alternatives since Festival is broken in fedora
diff --git a/drafts/skullman-text-to-speech.mdwn b/drafts/skullman-text-to-speech.mdwn
index cc339f0..968b2e8 100644
--- a/drafts/skullman-text-to-speech.mdwn
+++ b/drafts/skullman-text-to-speech.mdwn
@@ -139,5 +139,8 @@ Should further development be warranted other changes could include:
     `text2wave` exists to write to a file, possibly standard output,
     and `pacat` exists to take audio from standard input and put it to speakers,
     but I couldn't get it to work at the time.
+5.  Replace festival entirely.
+    It is in need of maintainership, and has been broken in Fedora releases,
+    so replacing the voice generation with pyttsx, espeak or flite could help.
 
 [RPi Text to Speech (Speech Synthesis)]: https://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis)

Rework installation description
diff --git a/drafts/skullman-text-to-speech.mdwn b/drafts/skullman-text-to-speech.mdwn
index 953a1f5..cc339f0 100644
--- a/drafts/skullman-text-to-speech.mdwn
+++ b/drafts/skullman-text-to-speech.mdwn
@@ -12,13 +12,14 @@ and deep down there after Cepstral it's) Festival of course!
 
 So how do we use that?
 
-Well, after installing it
+First we need to install it. Since I wrote this on an Ubuntu system I do:
 
 [[!format sh """
 $ apt install festival
 """]]
 
-we can see that it has a convenient `--tts` option!
+This installs the `festival` command,
+which has a convenient `--tts` option!
 
 [[!format sh """
 $ echo hello world | festival --tts

Remove superfluous bracket
diff --git a/drafts/skullman-text-to-speech.mdwn b/drafts/skullman-text-to-speech.mdwn
index a24dd55..953a1f5 100644
--- a/drafts/skullman-text-to-speech.mdwn
+++ b/drafts/skullman-text-to-speech.mdwn
@@ -113,7 +113,7 @@ while read -r REPLY; do
                 '(SayText "'"$REPLY"'")'
 done
 pacmd unload-module module-null-sink
-"""]]]
+"""]]
 
 1.  Run that in a terminal window.
 2.  Start your chat program.

Github's cheatsheet is a lying liar
diff --git a/drafts/skullman-text-to-speech.mdwn b/drafts/skullman-text-to-speech.mdwn
index 7a8e6fc..a24dd55 100644
--- a/drafts/skullman-text-to-speech.mdwn
+++ b/drafts/skullman-text-to-speech.mdwn
@@ -7,7 +7,7 @@ Why write an 11 line shell script to replace it of course!
 
 Our first port of call is of course to Google!
 So what is the first result for "linux text to speech"?
-(well for me it's [https://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis)])
+(well for me it's [RPi Text to Speech (Speech Synthesis)][])
 and deep down there after Cepstral it's) Festival of course!
 
 So how do we use that?
@@ -138,3 +138,5 @@ Should further development be warranted other changes could include:
     `text2wave` exists to write to a file, possibly standard output,
     and `pacat` exists to take audio from standard input and put it to speakers,
     but I couldn't get it to work at the time.
+
+[RPi Text to Speech (Speech Synthesis)]: https://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis)

Attempt to fix link
diff --git a/drafts/skullman-text-to-speech.mdwn b/drafts/skullman-text-to-speech.mdwn
index d8d079b..7a8e6fc 100644
--- a/drafts/skullman-text-to-speech.mdwn
+++ b/drafts/skullman-text-to-speech.mdwn
@@ -7,7 +7,7 @@ Why write an 11 line shell script to replace it of course!
 
 Our first port of call is of course to Google!
 So what is the first result for "linux text to speech"?
-(well for me it's https://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis))
+(well for me it's [https://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis)])
 and deep down there after Cepstral it's) Festival of course!
 
 So how do we use that?

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

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

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

Add stream of consciousness article
diff --git a/drafts/skullman-text-to-speech.mdwn b/drafts/skullman-text-to-speech.mdwn
new file mode 100644
index 0000000..d8d079b
--- /dev/null
+++ b/drafts/skullman-text-to-speech.mdwn
@@ -0,0 +1,140 @@
+[[!meta title="Text To Speech"]]
+[[!meta author="Richard Maw"]]
+[[!tag pulseaudio festival text-to-speech shell]]
+
+What do you do if you need to be present on a call but you've lost your voice?
+Why write an 11 line shell script to replace it of course!
+
+Our first port of call is of course to Google!
+So what is the first result for "linux text to speech"?
+(well for me it's https://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis))
+and deep down there after Cepstral it's) Festival of course!
+
+So how do we use that?
+
+Well, after installing it
+
+[[!format sh """
+$ apt install festival
+"""]]
+
+we can see that it has a convenient `--tts` option!
+
+[[!format sh """
+$ echo hello world | festival --tts
+"""]]
+
+This however has two problems:
+
+1.  It is fatiguing on the fingers to tweak the parameters and run the command.
+2.  The output of the command is to the speakers rather than a microphone.
+
+We can fix problem 1 with a trivial shell script
+to produce output after every line instead.
+
+[[!format sh """
+#!/bin/sh
+while read -r REPLY; do
+        printf %s "$REPLY" | festival --tts
+done
+"""]]
+
+The problem of outputting to a microphone is somewhat more involved.
+
+It's possible to loop your speaker output through a recording device
+in Pulse Audio by setting the recording device to a "Monitor" device.
+
+It's no doubt possible to drive this from the command-line,
+but since my chat software is graphical I've no problem using `pavucontrol`.
+
+Once the chat software is running the "Recording" tab
+and change the input device of the application.
+
+This works but is unsatisfying because you need a second output device
+otherwise other sounds will be broadcast
+and is prone to causing feedback.
+
+What we need is some kind of virtual microphone.
+As usual, the likes of Google and StackOverflow come to hand,
+and a virtual microphone is what Pulse Audio calls a "null sink".
+
+We can create a null sink and give it a recognisable name by running:
+
+[[!format sh """
+pacmd load-module module-null-sink sink_name=Festival
+pacmd update-sink-proplist Festival device.description=Festival
+"""]]
+
+Then we can remove it again by running:
+
+[[!format sh """
+pacmd unload-module module-null-sink
+"""]]
+
+So how do we get festival to play its output to that?
+
+We can't start the command, then tweak the parameters in `pavucontrol`
+because it doesn't run long enough to change that before it starts playing.
+
+We can play audio to a specified device with the `paplay` command,
+but how do we get Festival to output?
+
+Fortunately Festival lets you set some parameters in its scripting language.
+
+We need to pick a common audio format that `paplay` can read
+and `festival` can produce.
+We can set this with:
+
+[[!format lisp """
+(Parameter.set 'Audio_Required_Format 'aiff)
+"""]]
+
+We need to tell festival to play audio through a specified Pulse Audio device.
+The best way I could find to do this
+was setting `Audio_Method` to `Audio_Command`
+and `Audio_Command` to a `paplay` command.
+
+[[!format lisp """
+(Parameter.set 'Audio_Method 'Audio_Command)
+(Parameter.set 'Audio_Command "paplay $FILE --client-name=Festival --stream-name=Speech --device=Festival")
+"""]]
+
+Festival lets us run commands on its command-line so the final script we get is:
+
+[[!format sh """
+#!/bin/sh
+pacmd load-module module-null-sink sink_name=Festival
+pacmd update-sink-proplist Festival device.description=Festival
+while read -r REPLY; do
+        festival --batch \
+                '(Parameter.set '\''Audio_Required_Format '\''aiff)' \
+                '(Parameter.set '\''Audio_Method '\''Audio_Command)' \
+                '(Parameter.set '\''Audio_Command "paplay $FILE --client-name=Festival --stream-name=Speech --device=Festival")' \
+                '(SayText "'"$REPLY"'")'
+done
+pacmd unload-module module-null-sink
+"""]]]
+
+1.  Run that in a terminal window.
+2.  Start your chat program.
+3.  Start `pavucontrol` and change the input device of your program to Festival.
+4.  Type lines of text into the terminal to speak.
+
+---
+
+Since this was a project to achieve the goal of being able to participate
+in a group chat without being able to speak, development stopped there.
+
+Should further development be warranted other changes could include:
+
+1.  The module load and unload process is pretty fragile.
+    Would need to use an API that is tied to process lifetime
+    or at least unload by ID rather than name.
+2.  No escaping mechanism for `$REPLY`.
+    Would need to learn string escaping in lisp.
+3.  Lots of work done per line of text.
+    Festival has a server mode which could reduce the amount of work per line.
+4.  Investigate a way to pipe audio directly between Festival and Pulse Audio.
+    `text2wave` exists to write to a file, possibly standard output,
+    and `pacat` exists to take audio from standard input and put it to speakers,
+    but I couldn't get it to work at the time.

publishing
diff --git a/queue/20180328-coming-back-to-a-project.mdwn b/queue/20180328-coming-back-to-a-project.mdwn
deleted file mode 100644
index 4c59222..0000000
--- a/queue/20180328-coming-back-to-a-project.mdwn
+++ /dev/null
@@ -1,50 +0,0 @@
-[[!meta title="Coming back to a project"]]
-[[!meta author="Daniel Silverstone"]]
-
-We've spoken about how [you are not finished yet][notfinished] with your
-project, how to avoid [burning bridges][bridges] in conversation, how to tell if a
-project is [dead, or merely resting][deador], and on knowing
-[when to retire][retire] from a project.  Today I'd like to talk about coming
-back to a project which you have taken a hiatus from.
-
-Whether your break from a project was planned or unplanned, whether you were
-fundamental to a project's progress, or "just" a helper, your absence will
-have been felt by others associated with the project, even if they've not said
-anything.  It's always a nice thing to let anyone who ought to know, know that
-you have returned.  Depending on your level of integration into that project's
-community and the particulars of your absence, your own sense of privacy around
-any reasons, etc., it can be worth letting the community know a little of why
-you were away, and why that means that now you are back.
-
-If your time away was unannounced, unplanned, abrupt, or otherwise disruptive
-to the community, it can also help to mend things if you are prepared to
-apologise for your absence.  **NOTE** I am not saying you have to apologise or
-excuse the reasons why you were absent, merely to note to the community that
-you are sorry to have been away and that you look forward to reintegrating.
-
-Just like I'd recommend when you join a community, make a point of discussing
-what you intend to achieve in the short term, in case there's someone who wants
-to assist you or has been working on something similar.  Also make it clear if
-you've kept up passively with the community in your time away, or if you've
-essentially a blank for the period of your absence.  That can help others to
-decide if they need to tell you about things which might be important, or
-otherwise relevant, to your interests and plans.
-
-If you were specifically, and solely, responsible for certain things when you
-were previously part of the project, you should, ideally, go back and check if
-anyone has picked it up in your absence.  If so, make a point of thanking them,
-and asking them if they wish to continue with the work without you, share the
-burden with you, or pass the work back to you entirely.  If that responsibility
-was part of why you had a hiatus, ensure that you don't end up in a similar
-position again.
-
-There are many more suggestions I might make, but I'll leave you with one final
-one.  Don't expect the project you re-join to be the same project you left.  In
-your absence things will have progressed with respect to the project, others in
-the community, and yourself.  Don't be saddened by this, instead rejoice in the
-diversity of life and dig back in with gusto.
-
-[notfinished]: /posts/so-you-think-you-are-finished/
-[bridges]: /posts/bridge-fires/
-[deador]: /posts/dead-or-resting/
-[retire]: /posts/when-to-retire/

enqueue
diff --git a/drafts/kinnison-coming-back-to-a-project.mdwn b/queue/20180328-coming-back-to-a-project.mdwn
similarity index 100%
rename from drafts/kinnison-coming-back-to-a-project.mdwn
rename to queue/20180328-coming-back-to-a-project.mdwn

Add dks tweaks
diff --git a/drafts/kinnison-coming-back-to-a-project.mdwn b/drafts/kinnison-coming-back-to-a-project.mdwn
index 14e4ff7..4c59222 100644
--- a/drafts/kinnison-coming-back-to-a-project.mdwn
+++ b/drafts/kinnison-coming-back-to-a-project.mdwn
@@ -22,13 +22,13 @@ apologise for your absence.  **NOTE** I am not saying you have to apologise or
 excuse the reasons why you were absent, merely to note to the community that
 you are sorry to have been away and that you look forward to reintegrating.
 
-Just like I'd recommend when you join a community, make a point of (re)capping
+Just like I'd recommend when you join a community, make a point of discussing
 what you intend to achieve in the short term, in case there's someone who wants
 to assist you or has been working on something similar.  Also make it clear if
 you've kept up passively with the community in your time away, or if you've
 essentially a blank for the period of your absence.  That can help others to
-decide if they need to tell you about things which might be important/relevant
-to your interests / plans.
+decide if they need to tell you about things which might be important, or
+otherwise relevant, to your interests and plans.
 
 If you were specifically, and solely, responsible for certain things when you
 were previously part of the project, you should, ideally, go back and check if

Fix typo in linky
diff --git a/drafts/kinnison-coming-back-to-a-project.mdwn b/drafts/kinnison-coming-back-to-a-project.mdwn
index a8d0c60..14e4ff7 100644
--- a/drafts/kinnison-coming-back-to-a-project.mdwn
+++ b/drafts/kinnison-coming-back-to-a-project.mdwn
@@ -2,7 +2,7 @@
 [[!meta author="Daniel Silverstone"]]
 
 We've spoken about how [you are not finished yet][notfinished] with your
-project, how to avoid [burning bridged][] in conversation, how to tell if a
+project, how to avoid [burning bridges][bridges] in conversation, how to tell if a
 project is [dead, or merely resting][deador], and on knowing
 [when to retire][retire] from a project.  Today I'd like to talk about coming
 back to a project which you have taken a hiatus from.
@@ -45,6 +45,6 @@ the community, and yourself.  Don't be saddened by this, instead rejoice in the
 diversity of life and dig back in with gusto.
 
 [notfinished]: /posts/so-you-think-you-are-finished/
-[burning bridges]: /posts/bridge-fires/
+[bridges]: /posts/bridge-fires/
 [deador]: /posts/dead-or-resting/
 [retire]: /posts/when-to-retire/

Draft of coming back
diff --git a/drafts/kinnison-coming-back-to-a-project.mdwn b/drafts/kinnison-coming-back-to-a-project.mdwn
new file mode 100644
index 0000000..a8d0c60
--- /dev/null
+++ b/drafts/kinnison-coming-back-to-a-project.mdwn
@@ -0,0 +1,50 @@
+[[!meta title="Coming back to a project"]]
+[[!meta author="Daniel Silverstone"]]
+
+We've spoken about how [you are not finished yet][notfinished] with your
+project, how to avoid [burning bridged][] in conversation, how to tell if a
+project is [dead, or merely resting][deador], and on knowing
+[when to retire][retire] from a project.  Today I'd like to talk about coming
+back to a project which you have taken a hiatus from.
+
+Whether your break from a project was planned or unplanned, whether you were
+fundamental to a project's progress, or "just" a helper, your absence will
+have been felt by others associated with the project, even if they've not said
+anything.  It's always a nice thing to let anyone who ought to know, know that
+you have returned.  Depending on your level of integration into that project's
+community and the particulars of your absence, your own sense of privacy around
+any reasons, etc., it can be worth letting the community know a little of why
+you were away, and why that means that now you are back.
+
+If your time away was unannounced, unplanned, abrupt, or otherwise disruptive
+to the community, it can also help to mend things if you are prepared to
+apologise for your absence.  **NOTE** I am not saying you have to apologise or
+excuse the reasons why you were absent, merely to note to the community that
+you are sorry to have been away and that you look forward to reintegrating.
+
+Just like I'd recommend when you join a community, make a point of (re)capping
+what you intend to achieve in the short term, in case there's someone who wants
+to assist you or has been working on something similar.  Also make it clear if
+you've kept up passively with the community in your time away, or if you've
+essentially a blank for the period of your absence.  That can help others to
+decide if they need to tell you about things which might be important/relevant
+to your interests / plans.
+
+If you were specifically, and solely, responsible for certain things when you
+were previously part of the project, you should, ideally, go back and check if
+anyone has picked it up in your absence.  If so, make a point of thanking them,
+and asking them if they wish to continue with the work without you, share the
+burden with you, or pass the work back to you entirely.  If that responsibility
+was part of why you had a hiatus, ensure that you don't end up in a similar
+position again.
+
+There are many more suggestions I might make, but I'll leave you with one final
+one.  Don't expect the project you re-join to be the same project you left.  In
+your absence things will have progressed with respect to the project, others in
+the community, and yourself.  Don't be saddened by this, instead rejoice in the
+diversity of life and dig back in with gusto.
+
+[notfinished]: /posts/so-you-think-you-are-finished/
+[burning bridges]: /posts/bridge-fires/
+[deador]: /posts/dead-or-resting/
+[retire]: /posts/when-to-retire/

publishing
diff --git a/queue/20180321-famous-bugs.mdwn b/queue/20180321-famous-bugs.mdwn
deleted file mode 100644
index 00e4e35..0000000
--- a/queue/20180321-famous-bugs.mdwn
+++ /dev/null
@@ -1,27 +0,0 @@
-[[!meta title="Famous bugs"]]
-[[!meta author="Lars Wirzenius"]]
-[[!tag bug]]
-
-The history of computing has a number of famous bugs. It can be
-amusing to read about them. Here's a start:
-
-* The very [first recorded bug][] (1945)
-* The [Mariner 1][] crash (1962)
-* The [Therac-25][] radiation overdose (1985)
-* The [AT&T network][] failure (1990)
-* The [Pentium bug][] (1994)
-* The [Ariane 5][] rocket explosion (1996)
-* The [other Pentium bug][] (1997)
-* The [Mars climate orbiter][] crash (1999)
-
-[first recorded bug]: https://thenextweb.com/shareables/2013/09/18/the-very-first-computer-bug/
-[Mariner 1]: https://en.wikipedia.org/wiki/Mariner_1
-[Therac-25]: https://en.wikipedia.org/wiki/Therac-25
-[AT&T network]: http://www.phworld.org/history/attcrash.htm
-[Ariane 5]: http://www-users.math.umn.edu/~arnold/disasters/ariane.html
-[Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
-[other Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
-[Mars climate orbiter]: https://en.wikipedia.org/wiki/Mars_Climate_Orbiter
-
-What's your favourite bug? Please tell us in comments.
-

Queue famous bugs
diff --git a/drafts/liw-bugs.mdwn b/queue/20180321-famous-bugs.mdwn
similarity index 100%
rename from drafts/liw-bugs.mdwn
rename to queue/20180321-famous-bugs.mdwn

Add: ask for more
diff --git a/drafts/liw-bugs.mdwn b/drafts/liw-bugs.mdwn
index eb0827b..00e4e35 100644
--- a/drafts/liw-bugs.mdwn
+++ b/drafts/liw-bugs.mdwn
@@ -23,3 +23,5 @@ amusing to read about them. Here's a start:
 [other Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
 [Mars climate orbiter]: https://en.wikipedia.org/wiki/Mars_Climate_Orbiter
 
+What's your favourite bug? Please tell us in comments.
+

Fix: again
diff --git a/drafts/liw-bugs.mdwn b/drafts/liw-bugs.mdwn
index ccc45f0..eb0827b 100644
--- a/drafts/liw-bugs.mdwn
+++ b/drafts/liw-bugs.mdwn
@@ -17,7 +17,7 @@ amusing to read about them. Here's a start:
 [first recorded bug]: https://thenextweb.com/shareables/2013/09/18/the-very-first-computer-bug/
 [Mariner 1]: https://en.wikipedia.org/wiki/Mariner_1
 [Therac-25]: https://en.wikipedia.org/wiki/Therac-25
-[AT%T network]: http://www.phworld.org/history/attcrash.htm
+[AT&T network]: http://www.phworld.org/history/attcrash.htm
 [Ariane 5]: http://www-users.math.umn.edu/~arnold/disasters/ariane.html
 [Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
 [other Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug

Fix: other link
diff --git a/drafts/liw-bugs.mdwn b/drafts/liw-bugs.mdwn
index d5504fe..ccc45f0 100644
--- a/drafts/liw-bugs.mdwn
+++ b/drafts/liw-bugs.mdwn
@@ -8,7 +8,7 @@ amusing to read about them. Here's a start:
 * The very [first recorded bug][] (1945)
 * The [Mariner 1][] crash (1962)
 * The [Therac-25][] radiation overdose (1985)
-* The [AT%T network][] failure (1990)
+* The [AT&T network][] failure (1990)
 * The [Pentium bug][] (1994)
 * The [Ariane 5][] rocket explosion (1996)
 * The [other Pentium bug][] (1997)

Fix: link (better)
diff --git a/drafts/liw-bugs.mdwn b/drafts/liw-bugs.mdwn
index c9d65d2..d5504fe 100644
--- a/drafts/liw-bugs.mdwn
+++ b/drafts/liw-bugs.mdwn
@@ -19,7 +19,7 @@ amusing to read about them. Here's a start:
 [Therac-25]: https://en.wikipedia.org/wiki/Therac-25
 [AT%T network]: http://www.phworld.org/history/attcrash.htm
 [Ariane 5]: http://www-users.math.umn.edu/~arnold/disasters/ariane.html
+[Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
 [other Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
-[other Pentium]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
 [Mars climate orbiter]: https://en.wikipedia.org/wiki/Mars_Climate_Orbiter
 

Fix: link
diff --git a/drafts/liw-bugs.mdwn b/drafts/liw-bugs.mdwn
index fe130de..c9d65d2 100644
--- a/drafts/liw-bugs.mdwn
+++ b/drafts/liw-bugs.mdwn
@@ -19,7 +19,7 @@ amusing to read about them. Here's a start:
 [Therac-25]: https://en.wikipedia.org/wiki/Therac-25
 [AT%T network]: http://www.phworld.org/history/attcrash.htm
 [Ariane 5]: http://www-users.math.umn.edu/~arnold/disasters/ariane.html
-[Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
+[other Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
 [other Pentium]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
 [Mars climate orbiter]: https://en.wikipedia.org/wiki/Mars_Climate_Orbiter
 

Add: draft of list of bugs
diff --git a/drafts/liw-bugs.mdwn b/drafts/liw-bugs.mdwn
new file mode 100644
index 0000000..fe130de
--- /dev/null
+++ b/drafts/liw-bugs.mdwn
@@ -0,0 +1,25 @@
+[[!meta title="Famous bugs"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag bug]]
+
+The history of computing has a number of famous bugs. It can be
+amusing to read about them. Here's a start:
+
+* The very [first recorded bug][] (1945)
+* The [Mariner 1][] crash (1962)
+* The [Therac-25][] radiation overdose (1985)
+* The [AT%T network][] failure (1990)
+* The [Pentium bug][] (1994)
+* The [Ariane 5][] rocket explosion (1996)
+* The [other Pentium bug][] (1997)
+* The [Mars climate orbiter][] crash (1999)
+
+[first recorded bug]: https://thenextweb.com/shareables/2013/09/18/the-very-first-computer-bug/
+[Mariner 1]: https://en.wikipedia.org/wiki/Mariner_1
+[Therac-25]: https://en.wikipedia.org/wiki/Therac-25
+[AT%T network]: http://www.phworld.org/history/attcrash.htm
+[Ariane 5]: http://www-users.math.umn.edu/~arnold/disasters/ariane.html
+[Pentium bug]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
+[other Pentium]: https://en.wikipedia.org/wiki/Pentium_FDIV_bug
+[Mars climate orbiter]: https://en.wikipedia.org/wiki/Mars_Climate_Orbiter
+

publishing
diff --git a/queue/20180314-so-you-think-you-are-finished.mdwn b/queue/20180314-so-you-think-you-are-finished.mdwn
deleted file mode 100644
index 1812c69..0000000
--- a/queue/20180314-so-you-think-you-are-finished.mdwn
+++ /dev/null
@@ -1,18 +0,0 @@
-[[!meta title="So you think you are finished?"]]
-[[!meta author="Daniel Silverstone"]]
-
-It's not often that we just link to a single article, but sometimes that
-article is simply "worth it".  In this instance I recently read a posting
-by Loup Vaillant which made me think "This needs to be distributed to the
-yakking community" and so here we go…
-
-Loup wrote about what needs to happen when you think you're finished writing
-your free/open source project's code, and I think you should run over there
-right now and read it:
-[After your project is done — Loup Vaillant](http://loup-vaillant.fr/articles/after-your-project-is-done)
-
-If you're still here afterwards, well done.  Now go and look over any projects
-of your own which you consider "finished" and see if there's anything Loup
-hilighted which still needs to be done to them.  Maybe make a
-[next-action](https://www.brevedy.com/2014/02/19/organizing-next-actions/) to
-do something about it.

Enqueue my draft
diff --git a/drafts/kinnison-so-you-think-you-are-finished.mdwn b/queue/20180314-so-you-think-you-are-finished.mdwn
similarity index 100%
rename from drafts/kinnison-so-you-think-you-are-finished.mdwn
rename to queue/20180314-so-you-think-you-are-finished.mdwn

Draft for today
diff --git a/drafts/kinnison-so-you-think-you-are-finished.mdwn b/drafts/kinnison-so-you-think-you-are-finished.mdwn
new file mode 100644
index 0000000..1812c69
--- /dev/null
+++ b/drafts/kinnison-so-you-think-you-are-finished.mdwn
@@ -0,0 +1,18 @@
+[[!meta title="So you think you are finished?"]]
+[[!meta author="Daniel Silverstone"]]
+
+It's not often that we just link to a single article, but sometimes that
+article is simply "worth it".  In this instance I recently read a posting
+by Loup Vaillant which made me think "This needs to be distributed to the
+yakking community" and so here we go…
+
+Loup wrote about what needs to happen when you think you're finished writing
+your free/open source project's code, and I think you should run over there
+right now and read it:
+[After your project is done — Loup Vaillant](http://loup-vaillant.fr/articles/after-your-project-is-done)
+
+If you're still here afterwards, well done.  Now go and look over any projects
+of your own which you consider "finished" and see if there's anything Loup
+hilighted which still needs to be done to them.  Maybe make a
+[next-action](https://www.brevedy.com/2014/02/19/organizing-next-actions/) to
+do something about it.

publishing
diff --git a/queue/20180307-cycles.mdwn b/queue/20180307-cycles.mdwn
deleted file mode 100644
index 5b988da..0000000
--- a/queue/20180307-cycles.mdwn
+++ /dev/null
@@ -1,50 +0,0 @@
-[[!meta title="Cycles in development"]]
-[[!meta author="Lars Wirzenius"]]
-[[!tag workflow]]
-
-Software development tends to happen in cycles and it's good to be
-aware of this.
-
-The innermost cycle is the edit-build-test-debug loop. You write or
-change some code, you build the software (assuming a compiled
-language), and you run the software to test it, either manually or by
-using automated tests.
-
-Being the innermost cycle, it's probably where most of development
-time happens. It tends to pay to optimise it to make it as fast as
-possible. Each of the parts can be optimised. For editing, use an
-editor you like and are comforable with. Also, a keyboard you can type
-efficiently with. For building, use incremental building, and maybe
-turn off optimisation to make the build got faster. For testing, maybe
-run only the relevant tests, and make those run quickly.
-
-Other cycles are:
-
-* The TDD cycle: add a new test, add or change code to make test pass,
-  refactor. This tends to embed the edit-build-test-debug loop.
-  Usually at most minutes in length.
-
-* Adding a minimal user-visible change: a new feature is broken into
-  the smallest increment that makes the user's life better, and this
-  is then developed, often using a number of TDD cycles.
-
-* A "sprint" in Agile development: often a week or two or three, often
-  adds an entire user-visible feature or other change, or several.
-
-* A release cycle: often many weeks or months, adds significant new
-  features. The set of added features or other changes, and the length
-  of the release cycle are all often determined by business interests,
-  business strategy, and often ridiculed by developers. This sometimes
-  happens for open source projects too, however. For example, a Linux
-  distribution might synchronise its own release schedule with
-  multiple major, critical components it includes.
-
-* The maintenance cycle: after the software has been "finished", and
-  put into production, bugs and other misfeatures get fixed and once
-  there's enough of them, a new release is made and put into production.
-
-In each case, it is useful to know the intended and expected length of
-the cycle, and what needs to happen during the cycle, and what the
-intended and expected result should be. It is also useful to try to
-identify and remove unnecessary clutter from the cycles, to make
-things go smoothly.

Fix: date
diff --git a/queue/2018-03-07-cycles.mdwn b/queue/20180307-cycles.mdwn
similarity index 100%
rename from queue/2018-03-07-cycles.mdwn
rename to queue/20180307-cycles.mdwn

Queue cycles article
diff --git a/drafts/liw-cycles.mdwn b/queue/2018-03-07-cycles.mdwn
similarity index 100%
rename from drafts/liw-cycles.mdwn
rename to queue/2018-03-07-cycles.mdwn

Add: fluff on cycles
diff --git a/drafts/liw-cycles.mdwn b/drafts/liw-cycles.mdwn
new file mode 100644
index 0000000..5b988da
--- /dev/null
+++ b/drafts/liw-cycles.mdwn
@@ -0,0 +1,50 @@
+[[!meta title="Cycles in development"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag workflow]]
+
+Software development tends to happen in cycles and it's good to be
+aware of this.
+
+The innermost cycle is the edit-build-test-debug loop. You write or
+change some code, you build the software (assuming a compiled
+language), and you run the software to test it, either manually or by
+using automated tests.
+
+Being the innermost cycle, it's probably where most of development
+time happens. It tends to pay to optimise it to make it as fast as
+possible. Each of the parts can be optimised. For editing, use an
+editor you like and are comforable with. Also, a keyboard you can type
+efficiently with. For building, use incremental building, and maybe
+turn off optimisation to make the build got faster. For testing, maybe
+run only the relevant tests, and make those run quickly.
+
+Other cycles are:
+
+* The TDD cycle: add a new test, add or change code to make test pass,
+  refactor. This tends to embed the edit-build-test-debug loop.
+  Usually at most minutes in length.
+
+* Adding a minimal user-visible change: a new feature is broken into
+  the smallest increment that makes the user's life better, and this
+  is then developed, often using a number of TDD cycles.
+
+* A "sprint" in Agile development: often a week or two or three, often
+  adds an entire user-visible feature or other change, or several.
+
+* A release cycle: often many weeks or months, adds significant new
+  features. The set of added features or other changes, and the length
+  of the release cycle are all often determined by business interests,
+  business strategy, and often ridiculed by developers. This sometimes
+  happens for open source projects too, however. For example, a Linux
+  distribution might synchronise its own release schedule with
+  multiple major, critical components it includes.
+
+* The maintenance cycle: after the software has been "finished", and
+  put into production, bugs and other misfeatures get fixed and once
+  there's enough of them, a new release is made and put into production.
+
+In each case, it is useful to know the intended and expected length of
+the cycle, and what needs to happen during the cycle, and what the
+intended and expected result should be. It is also useful to try to
+identify and remove unnecessary clutter from the cycles, to make
+things go smoothly.

publishing
diff --git a/queue/20180221-git-workflow.mdwn b/queue/20180221-git-workflow.mdwn
deleted file mode 100644
index cbd20ab..0000000
--- a/queue/20180221-git-workflow.mdwn
+++ /dev/null
@@ -1,57 +0,0 @@
-[[!meta title="The only proper git workflow, use nothing else"]]
-[[!meta author="Lars Wirzenius"]]
-[[!tag git workflow]]
-
-The title of this article is intentionally provocative.
-
-Git is a flexible tool that allows many kinds of workflow for using
-it. Here is the workflow I favour for teams:
-
-* The `master` branch is meant to be always releasable.
-
-* Every commit in `master` MUST pass the full test suite, though not
-  all commits in merged change sets need to do that.
-
-* Changes are done in dedicated branches, which get merged to `master`
-  frequently - avoid long-lived branches, since they tend to result in
-  much effort having to be spent on resolving merge conflicts.
-
-    * If frequent merging is, for some reason, not an option, at least
-      rebase the branch onto current master frequently: at least
-      daily. This keeps conflicts fairly small.
-
-* Before merging a branch into `master`, rebase it onto `master` and
-  resolve any conflicts - also rebase the branch so it tells a clean
-  story of the change.
-
-    * `git rebase -i master` is a very powerful tool. Learn it.
-
-    * A clean story doesn't have commits that fix mistakes earlier in
-      the branch-to-be-merged, and introduces changes within the
-      branch in chunks of a suitable size, and in an order that makes
-      sense to the reader. Clean up "Fix typo in previous commit" type
-      of commits.
-
-* Update the `NEWS` file when merging into `master`. Also Debian
-  packaging files, if those are included in the source tree.
-
-[bumper]: http://git.liw.fi/bumper/
-
-* Tag releases using PGP signed, annotated tags. I use a tool called
-  [bumper][], which updates `NEWS`, `version.py`, `debian/changelog`,
-  tags a release, and updates the files again with with `+git`
-  appended to version number.
-
-    * Review, update `NEWS`, `debian/changelog` before running bumper
-      to make sure they're up to date.
-
-* Name branches and tags with a prefix `foo/` where `foo` is your
-  username, handle, or other identifier.
-
-* If `master` is broken, fixing it has highest priority for the
-  project.
-
-* If there is a need for the project to support older releases, create
-  a branch for each such, when needed, starting from the release's
-  tag. Treat release branches as `master` for that release.
-

Queue liw's work
diff --git a/drafts/liw-git-workflow.mdwn b/queue/20180221-git-workflow.mdwn
similarity index 100%
rename from drafts/liw-git-workflow.mdwn
rename to queue/20180221-git-workflow.mdwn

Add: draft of git workflow article
diff --git a/drafts/liw-git-workflow.mdwn b/drafts/liw-git-workflow.mdwn
new file mode 100644
index 0000000..cbd20ab
--- /dev/null
+++ b/drafts/liw-git-workflow.mdwn
@@ -0,0 +1,57 @@
+[[!meta title="The only proper git workflow, use nothing else"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag git workflow]]
+
+The title of this article is intentionally provocative.
+
+Git is a flexible tool that allows many kinds of workflow for using
+it. Here is the workflow I favour for teams:
+
+* The `master` branch is meant to be always releasable.
+
+* Every commit in `master` MUST pass the full test suite, though not
+  all commits in merged change sets need to do that.
+
+* Changes are done in dedicated branches, which get merged to `master`
+  frequently - avoid long-lived branches, since they tend to result in
+  much effort having to be spent on resolving merge conflicts.
+
+    * If frequent merging is, for some reason, not an option, at least
+      rebase the branch onto current master frequently: at least
+      daily. This keeps conflicts fairly small.
+
+* Before merging a branch into `master`, rebase it onto `master` and
+  resolve any conflicts - also rebase the branch so it tells a clean
+  story of the change.
+
+    * `git rebase -i master` is a very powerful tool. Learn it.
+
+    * A clean story doesn't have commits that fix mistakes earlier in
+      the branch-to-be-merged, and introduces changes within the
+      branch in chunks of a suitable size, and in an order that makes
+      sense to the reader. Clean up "Fix typo in previous commit" type
+      of commits.
+
+* Update the `NEWS` file when merging into `master`. Also Debian
+  packaging files, if those are included in the source tree.
+
+[bumper]: http://git.liw.fi/bumper/
+
+* Tag releases using PGP signed, annotated tags. I use a tool called
+  [bumper][], which updates `NEWS`, `version.py`, `debian/changelog`,
+  tags a release, and updates the files again with with `+git`
+  appended to version number.
+
+    * Review, update `NEWS`, `debian/changelog` before running bumper
+      to make sure they're up to date.
+
+* Name branches and tags with a prefix `foo/` where `foo` is your
+  username, handle, or other identifier.
+
+* If `master` is broken, fixing it has highest priority for the
+  project.
+
+* If there is a need for the project to support older releases, create
+  a branch for each such, when needed, starting from the release's
+  tag. Treat release branches as `master` for that release.
+

publishing
diff --git a/queue/20180207-bridge-fires.mdwn b/queue/20180207-bridge-fires.mdwn
deleted file mode 100644
index 9a8c7e9..0000000
--- a/queue/20180207-bridge-fires.mdwn
+++ /dev/null
@@ -1,96 +0,0 @@
-[[!meta title="Don't burn that bridge!"]]
-[[!meta author="Lars Wirzenius"]]
-[[!tag bridge calm]]
-
-You may be familiar with some variant of this scenario:
-
-> You're on a mailing list (or web forum or Google group or whatever),
-> where some topic you're interested in is being discussed. You see
-> someone saying something you think is wrong. You fire off a quick
-> reply telling them they're wrong, and move on to the next topic.
->
-> Later on, you get a reply, and for some reason they are upset at you
-> telling them they're wrong, and you get upset at how rude they are,
-> so you send another quick reply, putting them in their place. Who do
-> they think they are, spouting off falsehoods and being rude about
-> it.
->
-> The disagreement spirals and becomes hotter and more vicious each
-> iteration. What common ground there was in the beginning is soon
-> ruined by trenches, bomb craters, and barbed wire. Any bridges
-> between the parties are on fire. There's no hope for peace.
-
-This is called a flame war. It's not a good thing, but it's not
-uncommon in technical discussions on the Internet. Why does it happen
-and how can you avoid it?
-
-As someone covered in scars of many a flame war, here are my
-observations (entirely unsubstantiated by sources):
-
-* Flame wars happen because people try to be seen as being more
-  correct than others, or to be seen to win a disagreement. This often
-  happens online because the communication medium lacks emotional
-  bandwidth. It is difficult to express subtle emotions and cues over
-  a text-only channel, especially, or any one-way channel.
-
-  Disagreements spiral away more rarely in person, because in-person
-  communication contains a lot of unspoken parts, which signal things
-  like someone being upset, before the thing blows up entirely. In
-  text-only communication, one needs to express such cues more
-  explicitly, and be careful when reading to spot the more subtle
-  cues.
-
-* In online discussions around free software there are also often no
-  prior personal bonds between participants. Basically, they don't
-  know each other. This makes it harder to understand each other.
-
-* The hottest flame wars tend to happen in contexts where the
-  participants have the least to lose.
-
-Some advice (again, no sources):
-
-* Try hard to understand the other parties in a disagreement. The
-  technical term is empathy. You don't need to agree with them, but
-  you need to try to understand why they say what they say and how
-  they feel. As an example, I was once in a meeting where a co-worker
-  arrived badly late, and the boss was quite angry. It was quickly
-  spiralling into a real-life flame war, until someone pointed out that
-  the boss was upset because he needed to get us developers do certain
-  things, and people being late was making that harder to achieve, and
-  at the same time the co-worker who was late was mourning his dog
-  who'd been poorly for years and had recently committed suicide by
-  forcing open a 6th floor window and jumping out.
-
-* Try even harder to not express anger and other unconstructive
-  feelings, especially by attacking the other parties. Instead of
-  "you're wrong, and you're so stupid that the only reason you don't
-  suffocate is because breathing is an autonomous action that doesn't
-  require the brain, go jump into a frozen lake", say something like
-  "I don't agree with you, and I'm upset about this discussion so I'm
-  going to stop participating, at least for a while". And then don't
-  participate further.
-
-* Do express your emotions explicitly, if you think that'll mean
-  others will understand you better.
-
-* Try to find at least something constructive to say, and some common
-  ground. Just because someone is wrong about what the colour of the
-  bike shed should be, doesn't mean you have to disagree whether a
-  bike shed is useful.
-
-* Realise that shutting up doesn't mean you agree with the other
-  parties in a disagreement, and it doesn't mean you "lose" the
-  argument.
-
-* Apply [rule 6][] vigorously: write angry responses if it helps you
-  deal with your emotions, but don't send them. You can then spend the
-  rest of you life being smug about how badly other people have been
-  humiliated and shown to be wrong.
-
-[rule 6]: https://liw.fi/rules/
-
-Your homework for this week, should you choose to accept it, is to
-find an old flame war and read through it and see where the
-participants could've said something different and defuse the
-situation. You get bonus points if it's one which you've participated
-in yourself.

Fix: language
diff --git a/queue/20180207-bridge-fires.mdwn b/queue/20180207-bridge-fires.mdwn
index 0fb6042..9a8c7e9 100644
--- a/queue/20180207-bridge-fires.mdwn
+++ b/queue/20180207-bridge-fires.mdwn
@@ -5,9 +5,9 @@
 You may be familiar with some variant of this scenario:
 
 > You're on a mailing list (or web forum or Google group or whatever),
-> where some topic you're interested in. You see someone saying
-> something you think is wrong. You fire off a quick reply telling
-> them they're wrong, and move on to the next topic.
+> where some topic you're interested in is being discussed. You see
+> someone saying something you think is wrong. You fire off a quick
+> reply telling them they're wrong, and move on to the next topic.
 >
 > Later on, you get a reply, and for some reason they are upset at you
 > telling them they're wrong, and you get upset at how rude they are,

Queue bridge burning
diff --git a/drafts/liw-bridge-fires.mdwn b/queue/20180207-bridge-fires.mdwn
similarity index 100%
rename from drafts/liw-bridge-fires.mdwn
rename to queue/20180207-bridge-fires.mdwn

Fix: missing half-sentence
diff --git a/drafts/liw-bridge-fires.mdwn b/drafts/liw-bridge-fires.mdwn
index 19045d8..0fb6042 100644
--- a/drafts/liw-bridge-fires.mdwn
+++ b/drafts/liw-bridge-fires.mdwn
@@ -84,7 +84,8 @@ Some advice (again, no sources):
 
 * Apply [rule 6][] vigorously: write angry responses if it helps you
   deal with your emotions, but don't send them. You can then spend the
-  rest of you life being smug about how badly other people 
+  rest of you life being smug about how badly other people have been
+  humiliated and shown to be wrong.
 
 [rule 6]: https://liw.fi/rules/
 

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

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

Add: draft of bridge burning article
diff --git a/drafts/liw-bridge-fires.mdwn b/drafts/liw-bridge-fires.mdwn
new file mode 100644
index 0000000..19045d8
--- /dev/null
+++ b/drafts/liw-bridge-fires.mdwn
@@ -0,0 +1,95 @@
+[[!meta title="Don't burn that bridge!"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag bridge calm]]
+
+You may be familiar with some variant of this scenario:
+
+> You're on a mailing list (or web forum or Google group or whatever),
+> where some topic you're interested in. You see someone saying
+> something you think is wrong. You fire off a quick reply telling
+> them they're wrong, and move on to the next topic.
+>
+> Later on, you get a reply, and for some reason they are upset at you
+> telling them they're wrong, and you get upset at how rude they are,
+> so you send another quick reply, putting them in their place. Who do
+> they think they are, spouting off falsehoods and being rude about
+> it.
+>
+> The disagreement spirals and becomes hotter and more vicious each
+> iteration. What common ground there was in the beginning is soon
+> ruined by trenches, bomb craters, and barbed wire. Any bridges
+> between the parties are on fire. There's no hope for peace.
+
+This is called a flame war. It's not a good thing, but it's not
+uncommon in technical discussions on the Internet. Why does it happen
+and how can you avoid it?
+
+As someone covered in scars of many a flame war, here are my
+observations (entirely unsubstantiated by sources):
+
+* Flame wars happen because people try to be seen as being more
+  correct than others, or to be seen to win a disagreement. This often
+  happens online because the communication medium lacks emotional
+  bandwidth. It is difficult to express subtle emotions and cues over
+  a text-only channel, especially, or any one-way channel.
+
+  Disagreements spiral away more rarely in person, because in-person
+  communication contains a lot of unspoken parts, which signal things
+  like someone being upset, before the thing blows up entirely. In
+  text-only communication, one needs to express such cues more
+  explicitly, and be careful when reading to spot the more subtle
+  cues.
+
+* In online discussions around free software there are also often no
+  prior personal bonds between participants. Basically, they don't
+  know each other. This makes it harder to understand each other.
+
+* The hottest flame wars tend to happen in contexts where the
+  participants have the least to lose.
+
+Some advice (again, no sources):
+
+* Try hard to understand the other parties in a disagreement. The
+  technical term is empathy. You don't need to agree with them, but
+  you need to try to understand why they say what they say and how
+  they feel. As an example, I was once in a meeting where a co-worker
+  arrived badly late, and the boss was quite angry. It was quickly
+  spiralling into a real-life flame war, until someone pointed out that
+  the boss was upset because he needed to get us developers do certain
+  things, and people being late was making that harder to achieve, and
+  at the same time the co-worker who was late was mourning his dog
+  who'd been poorly for years and had recently committed suicide by
+  forcing open a 6th floor window and jumping out.
+
+* Try even harder to not express anger and other unconstructive
+  feelings, especially by attacking the other parties. Instead of
+  "you're wrong, and you're so stupid that the only reason you don't
+  suffocate is because breathing is an autonomous action that doesn't
+  require the brain, go jump into a frozen lake", say something like
+  "I don't agree with you, and I'm upset about this discussion so I'm
+  going to stop participating, at least for a while". And then don't
+  participate further.
+
+* Do express your emotions explicitly, if you think that'll mean
+  others will understand you better.
+
+* Try to find at least something constructive to say, and some common
+  ground. Just because someone is wrong about what the colour of the
+  bike shed should be, doesn't mean you have to disagree whether a
+  bike shed is useful.
+
+* Realise that shutting up doesn't mean you agree with the other
+  parties in a disagreement, and it doesn't mean you "lose" the
+  argument.
+
+* Apply [rule 6][] vigorously: write angry responses if it helps you
+  deal with your emotions, but don't send them. You can then spend the
+  rest of you life being smug about how badly other people 
+
+[rule 6]: https://liw.fi/rules/
+
+Your homework for this week, should you choose to accept it, is to
+find an old flame war and read through it and see where the
+participants could've said something different and defuse the
+situation. You get bonus points if it's one which you've participated
+in yourself.

publishing
diff --git a/queue/20180201-processing-input.mdwn b/queue/20180201-processing-input.mdwn
deleted file mode 100644
index 7081bc0..0000000
--- a/queue/20180201-processing-input.mdwn
+++ /dev/null
@@ -1,86 +0,0 @@
-[[!meta title="Processing input"]]
-[[!meta author="Daniel Silverstone"]]
-
-Computer programs typically need some input on which to perform their
-purpose.  In order to ascribe meaning to the input, programs will perform a
-process called parsing.  Depending on exactly how the author chooses to
-develop their program, there are a number of fundamentally different ways to
-convert a byte sequence to something with more semantic information layered
-on top.
-
-Lexing and Parsing
-==================
-
-[Lexical analysis][] is the process by which a program takes a stream of bytes
-and converts it to a stream of [tokens][].  Tokens have a little more meaning,
-such as taking the byte sequence `"Hello"` and representing it as a token of
-the form `STRING` whose value is `Hello`.  Once a byte stream has been turned
-into a token stream, the program can then parse the token stream.
-
-Typically, the [parsing][] process consumes the token stream and produces as
-its output something like an [abstract syntax tree][].  This AST layers enough
-semantic meaning onto the input to allow the program to make use of the input
-properly.  As an example, in the right context, a parser might take a token
-stream of the form `STRING(println) '(' STRING(Hello) ')' ';'` and turn it into
-an AST node of the form `FunctionInvocation("println", [ "Hello" ])`.  As you
-can see, that would be far more useful if the program in question is a
-compiler.
-
-Parsing in this way is commonly applied when the language [grammar][] in
-question meets certain rules which allow it to be expressed in such a way that
-a token stream can be unambiguously converted to the AST with no more than one
-"look-ahead" token.  Such languages can convert "left-to-right"
-i.e. unidirectionally along the token stream and usually we call those
-languages [LALR(1)][].
-
-To facilitate easy lexical analysis and the generation of `LALR(1)` parsers,
-there exist a number of generator programs such as `flex` and `bison`, or
-`re2c` and `lemon`.  Indeed such generators are available for non-C languages
-such as `alex` and `happy` for Haskell, or `PLY` for Python.
-
-Parsing Expression Grammars
-===========================
-
-[PEGs][] are a type of parser which typically end up represented as a
-[recursive descent][] parser.  PEGs sometimes allow for a parser to be
-represented in a way which is more natural for the language definer.  Further, 
-there is effectively infinite capability for look-ahead when using PEGs, allowing
-them to parse grammars which a more traditional `LALR(1)` would be unable to.
-
-Combinatory Parsing
-===================
-
-[Parser combinators][] take advantage of higher order functions in programming
-languages to allow a parser to be built up by combining smaller parsers
-together into more complex parsers, until a full parser for the input can be
-built.  The lowest level building blocks of such parsers are often called
-terminal recognisers and they recognise the smallest possible building block of
-the input (which could be a token from a lexical analyser or could be a byte or
-unicode character).  Most parser combinator libraries offer a number of
-standard combinators, such as one which will recognise one or more of the
-passed in parser, returning the recognised elements as a list.
-
-Sadly, due to the strong functional programming nature of combinators, it's
-often very hard to statically analyse the parser to check for ambiguities or
-inconsistencies in the grammar.  These issues only tend to become obvious at
-runtime, meaning that if you're using parser combinators to build your parser,
-it's recommended that you carefully write your grammar first, and convert it
-to code second.
-
-Homework
-========
-
-Find a program which you use, which consumes input in a form specific to the
-program itself.  (Or find a library which is meant to parse some format) and
-take a deep look at how it performs lexical analysis and parsing.
-
-
-[parsing]: https://en.wikipedia.org/wiki/Parsing
-[Lexical analysis]: https://en.wikipedia.org/wiki/Lexical_analysis
-[tokens]: https://en.wikipedia.org/wiki/Lexical_analysis#Token
-[abstract syntax tree]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
-[grammar]: https://en.wikipedia.org/wiki/Formal_grammar
-[LALR(1)]: https://en.wikipedia.org/wiki/LALR_parser
-[PEGs]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
-[recursive descent]: https://en.wikipedia.org/wiki/Recursive_descent_parser
-[Parser combinators]: https://en.wikipedia.org/wiki/Parser_combinator

publishing
diff --git a/queue/20180124-dead-or-resting.mdwn b/queue/20180124-dead-or-resting.mdwn
deleted file mode 100644
index 9ed2eb0..0000000
--- a/queue/20180124-dead-or-resting.mdwn
+++ /dev/null
@@ -1,52 +0,0 @@
-[[!meta title="Is it dead, or is it just resting?"]]
-[[!meta author="Daniel Silverstone"]]
-
-There are any number of metrics, heuristics, entrail-reading techniques, etc.
-which can be used to determine whether or not a project is "alive" for a
-variety of meanings of that word.  Depending on what you need to use a project
-for, you might need to make such an assessment and so this week I'd like to
-give you a few ways to assess a software project's "liveness".  In addition,
-you might be a project developer who needs to assess the "liveness" of
-something you're working on yourself. (For example, to check it's well organised
-for your expected user-base).
-
-If you're trying to use a project in a production situation, then you likely
-want to look to whether the codebase is relatively stable, whether it makes
-sensibly structured releases with some kind of semantic versioning, what its
-tracker looks like (relatively few open *BUGS*, short times between bug reports
-and fixes), and what its documentation looks like.  You may also look for
-evidence that others rely on the project, but that's perhaps less important.
-It's fine for the codebase to have a lot of churn providing there seems to be
-some commitment to a stable/reliable interface (be that a CLI or an API).
-
-If, on the other hand, you're looking for a project to use in a fairly
-experimental situation, you may be looking for a project whose developers are
-very active and responding well to feature requests, bug reports, etc., however,
-here the number of open bugs is much less relevant than the way in which the
-developers react to new uses of their codebase.
-
-If you're looking for a project to contribute to, then assuming you've already
-determined your own interest in the project to be high, I'd suggest that you
-look to the developers/community: how active (or otherwise) they are, how
-well they respond to comments/queries/issues/bugs etc..  A project which is
-beautifully written but whose developers take months over responding to simple
-queries might not be suitable for you to join.  On the other hand, a nicely
-written project whose developers are essentially absent is very much ripe for
-an offer of adoption and/or simple forking.
-
-(As a corollary, if you're a project developer and someone turns up looking at
-your project and you know it's not right for them,
-[consider pointing them somewhere else](http://blog.petdance.com/2018/01/02/the-best-open-source-project-for-someone-might-not-be-yours-and-thats-ok/).)
-
-So, in summary, useful things to look at include:
-
-* The churn in the project codebase
-* Whether the project has adopted semantic versioning
-* Whether the project makes lots of bugfix releases or seems stable
-* How well the project team responds to new issues/bugs
-* How well the project accepts contributions.
-
-This week your homework is to assess a project you're part of, with the eyes of
-someone who might be coming to it to use/contribute-to.  See if you can find
-ways you could improve your own projects, and give it a go.
-

Queue articles
diff --git a/drafts/kinnison-dead-or-resting.mdwn b/queue/20180124-dead-or-resting.mdwn
similarity index 100%
rename from drafts/kinnison-dead-or-resting.mdwn
rename to queue/20180124-dead-or-resting.mdwn
diff --git a/drafts/kinnison-processing-input.mdwn b/queue/20180201-processing-input.mdwn
similarity index 100%
rename from drafts/kinnison-processing-input.mdwn
rename to queue/20180201-processing-input.mdwn

publishing
diff --git a/queue/20180117-msg-trunc.mdwn b/queue/20180117-msg-trunc.mdwn
deleted file mode 100644
index d5ea8d9..0000000
--- a/queue/20180117-msg-trunc.mdwn
+++ /dev/null
@@ -1,126 +0,0 @@
-[[!meta title="MSG_TRUNC is poorly supported"]]
-[[!meta author="Richard Maw"]]
-[[!tag C Linux syscall python]]
-
-`ssize = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC)`
-lets you see how big the next message in a UDP or UNIX socket's buffer is.
-
-This can be important
-if your application-level communications can support variable message sizes,
-since you need to be able to provide a buffer large enough for the data,
-but preferrably not too much larger that it wastes memory.
-
-Unfortunately, a lot of programming languages' bindings don't make this easy.
-
----
-
-Python's approach is to allocate a buffer of the provided size,
-and then reallocate to the returned size afterwards,
-and return the buffer.
-
-This behaviour is intended to permit a larger allocation to begin with,
-but as a side-effect it also permits a smaller one to not break horribly.
-
-Well, mostly. In Python 2 it breaks horribly.
-
-[[!format sh """
-$ python -c 'import socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
-s.bind("/tmp/testsock")
-s.recv(0, socket.MSG_PEEK|socket.MSG_TRUNC)'
-Traceback (most recent call last):
-  File "<string>", line 4, in <module>
-SystemError: ../Objects/stringobject.c:3909: bad argument to internal function
-"""]]
-
-Python 3 instead returns an empty buffer immediately before reading the socket.
-
-[[!format sh """
-$ python3 -c 'import socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
-s.bind("/tmp/testsock")
-m = s.recv(0, socket.MSG_PEEK|socket.MSG_TRUNC)
-print(len(m), m)'
-0 b''
-"""]]
-
-You can work around this by receiving a minimum length of 1.
-
-[[!format sh """
-$ python -c 'import socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
-s.bind("/tmp/testsock")
-m = s.recv(1, socket.MSG_PEEK|socket.MSG_TRUNC)
-print(len(m), m)'
-(4, 'a\x00n\x00')
-"""]]
-
-The returned buffer's length is that of the message,
-though most of the buffer's contents is junk.
-
-The reason these interfaces aren't great
-is that they return an object rather than using a provided one,
-and it would be unpleasant for it to return a different type based on its flags.
-
-Python has an alternative interface in the form of [socket.recv_into][],
-which should fare better, since it can return the size separately,
-it should be able to translate a `None` buffer into a `NULL` pointer.
-
-[[!format sh """
-$ python -c 'import socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
-s.bind("/tmp/testsock")
-m = s.recv_into(None, 0, socket.MSG_PEEK|socket.MSG_TRUNC)
-print(m)'
-Traceback (most recent call last):
-  File "<string>", line 4, in <module>
-TypeError: recv_into() argument 1 must be read-write buffer, not None
-"""]]
-
-Unfortunately, this proves not to be the case.
-
-In Python 2 we can re-use a "null byte array" for this purpose.
-
-[[!format sh """
-$ python -c 'import socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
-s.bind("/tmp/testsock")
-nullbytearray = bytearray()
-m = s.recv_into(nullbytearray, 0, socket.MSG_PEEK|socket.MSG_TRUNC)
-print(m)'
-4
-"""]]
-
-Unfortunately, Python 3 decided to be clever.
-
-[[!format sh """
-$ python3 -c 'import socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
-s.bind("/tmp/testsock")
-nullbytearray = bytearray()
-m = s.recv_into(nullbytearray, 0, socket.MSG_PEEK|socket.MSG_TRUNC)
-print(m)'
-0
-"""]]
-
-Like with plain `recv` it returns early without waiting for the message.
-
-I had hoped to provide a counter-example of a programming language
-that provided a way to expose this as part of its standard library.
-
-Distressingly, the best behaved standard libraries
-were the ones that exposed the system calls directly
-with all the lack of safety guarantees that implies.
-
----
-
-In conclusion, `MSG_TRUNC` is a thing you can do on Linux.
-
-If you want to use it from a higher-level language than C
-you won't find a good interface for it in the standard library.
-
-If you find yourself in a position to design a language,
-please bear in mind people may want to do this on Linux,
-so at least provide access to the un-mangled system call interface.
-
-[socket.recv_into]: https://docs.python.org/3/library/socket.html#socket.socket.recv_into

enqueue article
diff --git a/drafts/skullman-msg-trunc.mdwn b/queue/20180117-msg-trunc.mdwn
similarity index 100%
rename from drafts/skullman-msg-trunc.mdwn
rename to queue/20180117-msg-trunc.mdwn

publishing
diff --git a/queue/20180110-when-to-retire.mdwn b/queue/20180110-when-to-retire.mdwn
deleted file mode 100644
index d2202cd..0000000
--- a/queue/20180110-when-to-retire.mdwn
+++ /dev/null
@@ -1,31 +0,0 @@
-[[!meta title="Knowing when to retire from a project"]]
-[[!meta author="Lars Wirzenius"]]
-
-A few months ago we published an article on
-[[how to retire|/posts/retiring/]]. It was followed by my decision to
-[retire Obnam](https://blog.liw.fi/posts/2017/08/13/retiring_obnam).
-Today, we will discuss how you know you should retire from a free
-software project.
-
-Here are some possible reasons:
-
-* It's no longer fun.
-* You no longer have time for it.
-* It's no longer a useful project.
-* It requires hardware you no longer have.
-* You don't like the technical decisions made in the project and
-  changing them now would be too much work.
-* The project has no users anymore.
-* You have a falling out with the other contributors.
-* You just don't want to work on the project anymore.
-* You win the lottery and can't be bothered to do anything anymore.
-* You become enlightened and realise that computers are preventing you
-  from becoming happy, so you give away everything you have, and move
-  into a cave to meditate.
-* The project is finished and requires no more work: it has all the
-  features its users need, and all bugs have been fixed.
-
-You may also like the talk [Consensually doing things together?][] by
-Enrico Zini from the 2017 Debconf.
-
-[Consensually doing things together?]: https://debconf17.debconf.org/talks/92/

Language fixes
diff --git a/drafts/skullman-msg-trunc.mdwn b/drafts/skullman-msg-trunc.mdwn
index f72694e..d5ea8d9 100644
--- a/drafts/skullman-msg-trunc.mdwn
+++ b/drafts/skullman-msg-trunc.mdwn
@@ -10,11 +10,11 @@ if your application-level communications can support variable message sizes,
 since you need to be able to provide a buffer large enough for the data,
 but preferrably not too much larger that it wastes memory.
 
-Unfortunately a lot of programming language's bindings don't make this easy.
+Unfortunately, a lot of programming languages' bindings don't make this easy.
 
 ---
 
-Python's approach is allocate a buffer of the provided size,
+Python's approach is to allocate a buffer of the provided size,
 and then reallocate to the returned size afterwards,
 and return the buffer.
 
@@ -77,7 +77,7 @@ Traceback (most recent call last):
 TypeError: recv_into() argument 1 must be read-write buffer, not None
 """]]
 
-Unfortunately this proves not to be the case.
+Unfortunately, this proves not to be the case.
 
 In Python 2 we can re-use a "null byte array" for this purpose.
 
@@ -91,7 +91,7 @@ print(m)'
 4
 """]]
 
-Unfortunately Python 3 decided to be clever.
+Unfortunately, Python 3 decided to be clever.
 
 [[!format sh """
 $ python3 -c 'import socket
@@ -106,15 +106,15 @@ print(m)'
 Like with plain `recv` it returns early without waiting for the message.
 
 I had hoped to provide a counter-example of a programming language
-that provided as part of its standard library a way to expose this.
+that provided a way to expose this as part of its standard library.
 
-Distressingly the best behaved standard libraries
+Distressingly, the best behaved standard libraries
 were the ones that exposed the system calls directly
 with all the lack of safety guarantees that implies.
 
 ---
 
-MSG_TRUNC is a thing you can do on Linux.
+In conclusion, `MSG_TRUNC` is a thing you can do on Linux.
 
 If you want to use it from a higher-level language than C
 you won't find a good interface for it in the standard library.

Queue Liw's retiring
diff --git a/drafts/liw-when-to-retire.mdwn b/queue/20180110-when-to-retire.mdwn
similarity index 100%
rename from drafts/liw-when-to-retire.mdwn
rename to queue/20180110-when-to-retire.mdwn

Fixes as suggested by Lesley
diff --git a/drafts/kinnison-dead-or-resting.mdwn b/drafts/kinnison-dead-or-resting.mdwn
index bd32007..9ed2eb0 100644
--- a/drafts/kinnison-dead-or-resting.mdwn
+++ b/drafts/kinnison-dead-or-resting.mdwn
@@ -1,16 +1,16 @@
 [[!meta title="Is it dead, or is it just resting?"]]
 [[!meta author="Daniel Silverstone"]]
 
-There are any number of metrics, heuristics, entrail-reading techniques, etc
+There are any number of metrics, heuristics, entrail-reading techniques, etc.
 which can be used to determine whether or not a project is "alive" for a
 variety of meanings of that word.  Depending on what you need to use a project
 for, you might need to make such an assessment and so this week I'd like to
 give you a few ways to assess a software project's "liveness".  In addition,
 you might be a project developer who needs to assess the "liveness" of
-something you're working on yourself. (For example to check it's well organised
+something you're working on yourself. (For example, to check it's well organised
 for your expected user-base).
 
-If you're trying to use a project in a production situation then you likely
+If you're trying to use a project in a production situation, then you likely
 want to look to whether the codebase is relatively stable, whether it makes
 sensibly structured releases with some kind of semantic versioning, what its
 tracker looks like (relatively few open *BUGS*, short times between bug reports
@@ -21,14 +21,14 @@ some commitment to a stable/reliable interface (be that a CLI or an API).
 
 If, on the other hand, you're looking for a project to use in a fairly
 experimental situation, you may be looking for a project whose developers are
-very active and responding well to feature requests, bug reports, etc, but
-where the number of open bugs is much less relevant than the way that the
+very active and responding well to feature requests, bug reports, etc., however,
+here the number of open bugs is much less relevant than the way in which the
 developers react to new uses of their codebase.
 
 If you're looking for a project to contribute to, then assuming you've already
 determined your own interest in the project to be high, I'd suggest that you
-look to how the developers/community, how active (or otherwise) they are, how
-well they respond to comments/queries/issues/bugs etc.  A project which is
+look to the developers/community: how active (or otherwise) they are, how
+well they respond to comments/queries/issues/bugs etc..  A project which is
 beautifully written but whose developers take months over responding to simple
 queries might not be suitable for you to join.  On the other hand, a nicely
 written project whose developers are essentially absent is very much ripe for
diff --git a/drafts/kinnison-processing-input.mdwn b/drafts/kinnison-processing-input.mdwn
index 3a33fab..7081bc0 100644
--- a/drafts/kinnison-processing-input.mdwn
+++ b/drafts/kinnison-processing-input.mdwn
@@ -1,7 +1,7 @@
 [[!meta title="Processing input"]]
 [[!meta author="Daniel Silverstone"]]
 
-Computer programs typically need some input over which to perform their
+Computer programs typically need some input on which to perform their
 purpose.  In order to ascribe meaning to the input, programs will perform a
 process called parsing.  Depending on exactly how the author chooses to
 develop their program, there are a number of fundamentally different ways to
@@ -43,9 +43,9 @@ Parsing Expression Grammars
 
 [PEGs][] are a type of parser which typically end up represented as a
 [recursive descent][] parser.  PEGs sometimes allow for a parser to be
-represented in a way which is more natural for the language definer.  PEGs also
-have effectively got infinite look-ahead, allowing them to parse grammars which
-a more traditional `LALR(1)` would be unable to.
+represented in a way which is more natural for the language definer.  Further, 
+there is effectively infinite capability for look-ahead when using PEGs, allowing
+them to parse grammars which a more traditional `LALR(1)` would be unable to.
 
 Combinatory Parsing
 ===================

Remove obvious scaffolding structures
diff --git a/drafts/skullman-msg-trunc.mdwn b/drafts/skullman-msg-trunc.mdwn
index 19ef625..f72694e 100644
--- a/drafts/skullman-msg-trunc.mdwn
+++ b/drafts/skullman-msg-trunc.mdwn
@@ -1,4 +1,4 @@
-[[!meta title="TODO - MSG_TRUNC is poorly supported"]]
+[[!meta title="MSG_TRUNC is poorly supported"]]
 [[!meta author="Richard Maw"]]
 [[!tag C Linux syscall python]]
 
@@ -114,8 +114,6 @@ with all the lack of safety guarantees that implies.
 
 ---
 
-Conclusion:
-
 MSG_TRUNC is a thing you can do on Linux.
 
 If you want to use it from a higher-level language than C

Add draft about MSG_TRUNC
diff --git a/drafts/skullman-msg-trunc.mdwn b/drafts/skullman-msg-trunc.mdwn
new file mode 100644
index 0000000..19ef625
--- /dev/null
+++ b/drafts/skullman-msg-trunc.mdwn
@@ -0,0 +1,128 @@
+[[!meta title="TODO - MSG_TRUNC is poorly supported"]]
+[[!meta author="Richard Maw"]]
+[[!tag C Linux syscall python]]
+
+`ssize = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC)`
+lets you see how big the next message in a UDP or UNIX socket's buffer is.
+
+This can be important
+if your application-level communications can support variable message sizes,
+since you need to be able to provide a buffer large enough for the data,
+but preferrably not too much larger that it wastes memory.
+
+Unfortunately a lot of programming language's bindings don't make this easy.
+
+---
+
+Python's approach is allocate a buffer of the provided size,
+and then reallocate to the returned size afterwards,
+and return the buffer.
+
+This behaviour is intended to permit a larger allocation to begin with,
+but as a side-effect it also permits a smaller one to not break horribly.
+
+Well, mostly. In Python 2 it breaks horribly.
+
+[[!format sh """
+$ python -c 'import socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+s.bind("/tmp/testsock")
+s.recv(0, socket.MSG_PEEK|socket.MSG_TRUNC)'
+Traceback (most recent call last):
+  File "<string>", line 4, in <module>
+SystemError: ../Objects/stringobject.c:3909: bad argument to internal function
+"""]]
+
+Python 3 instead returns an empty buffer immediately before reading the socket.
+
+[[!format sh """
+$ python3 -c 'import socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+s.bind("/tmp/testsock")
+m = s.recv(0, socket.MSG_PEEK|socket.MSG_TRUNC)
+print(len(m), m)'
+0 b''
+"""]]
+
+You can work around this by receiving a minimum length of 1.
+
+[[!format sh """
+$ python -c 'import socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+s.bind("/tmp/testsock")
+m = s.recv(1, socket.MSG_PEEK|socket.MSG_TRUNC)
+print(len(m), m)'
+(4, 'a\x00n\x00')
+"""]]
+
+The returned buffer's length is that of the message,
+though most of the buffer's contents is junk.
+
+The reason these interfaces aren't great
+is that they return an object rather than using a provided one,
+and it would be unpleasant for it to return a different type based on its flags.
+
+Python has an alternative interface in the form of [socket.recv_into][],
+which should fare better, since it can return the size separately,
+it should be able to translate a `None` buffer into a `NULL` pointer.
+
+[[!format sh """
+$ python -c 'import socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+s.bind("/tmp/testsock")
+m = s.recv_into(None, 0, socket.MSG_PEEK|socket.MSG_TRUNC)
+print(m)'
+Traceback (most recent call last):
+  File "<string>", line 4, in <module>
+TypeError: recv_into() argument 1 must be read-write buffer, not None
+"""]]
+
+Unfortunately this proves not to be the case.
+
+In Python 2 we can re-use a "null byte array" for this purpose.
+
+[[!format sh """
+$ python -c 'import socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+s.bind("/tmp/testsock")
+nullbytearray = bytearray()
+m = s.recv_into(nullbytearray, 0, socket.MSG_PEEK|socket.MSG_TRUNC)
+print(m)'
+4
+"""]]
+
+Unfortunately Python 3 decided to be clever.
+
+[[!format sh """
+$ python3 -c 'import socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+s.bind("/tmp/testsock")
+nullbytearray = bytearray()
+m = s.recv_into(nullbytearray, 0, socket.MSG_PEEK|socket.MSG_TRUNC)
+print(m)'
+0
+"""]]
+
+Like with plain `recv` it returns early without waiting for the message.
+
+I had hoped to provide a counter-example of a programming language
+that provided as part of its standard library a way to expose this.
+
+Distressingly the best behaved standard libraries
+were the ones that exposed the system calls directly
+with all the lack of safety guarantees that implies.
+
+---
+
+Conclusion:
+
+MSG_TRUNC is a thing you can do on Linux.
+
+If you want to use it from a higher-level language than C
+you won't find a good interface for it in the standard library.
+
+If you find yourself in a position to design a language,
+please bear in mind people may want to do this on Linux,
+so at least provide access to the un-mangled system call interface.
+
+[socket.recv_into]: https://docs.python.org/3/library/socket.html#socket.socket.recv_into

Processing input draft
diff --git a/drafts/kinnison-processing-input.mdwn b/drafts/kinnison-processing-input.mdwn
new file mode 100644
index 0000000..3a33fab
--- /dev/null
+++ b/drafts/kinnison-processing-input.mdwn
@@ -0,0 +1,86 @@
+[[!meta title="Processing input"]]
+[[!meta author="Daniel Silverstone"]]
+
+Computer programs typically need some input over which to perform their
+purpose.  In order to ascribe meaning to the input, programs will perform a
+process called parsing.  Depending on exactly how the author chooses to
+develop their program, there are a number of fundamentally different ways to
+convert a byte sequence to something with more semantic information layered
+on top.
+
+Lexing and Parsing
+==================
+
+[Lexical analysis][] is the process by which a program takes a stream of bytes
+and converts it to a stream of [tokens][].  Tokens have a little more meaning,
+such as taking the byte sequence `"Hello"` and representing it as a token of
+the form `STRING` whose value is `Hello`.  Once a byte stream has been turned
+into a token stream, the program can then parse the token stream.
+
+Typically, the [parsing][] process consumes the token stream and produces as
+its output something like an [abstract syntax tree][].  This AST layers enough
+semantic meaning onto the input to allow the program to make use of the input
+properly.  As an example, in the right context, a parser might take a token
+stream of the form `STRING(println) '(' STRING(Hello) ')' ';'` and turn it into
+an AST node of the form `FunctionInvocation("println", [ "Hello" ])`.  As you
+can see, that would be far more useful if the program in question is a
+compiler.
+
+Parsing in this way is commonly applied when the language [grammar][] in
+question meets certain rules which allow it to be expressed in such a way that
+a token stream can be unambiguously converted to the AST with no more than one
+"look-ahead" token.  Such languages can convert "left-to-right"
+i.e. unidirectionally along the token stream and usually we call those
+languages [LALR(1)][].
+
+To facilitate easy lexical analysis and the generation of `LALR(1)` parsers,
+there exist a number of generator programs such as `flex` and `bison`, or
+`re2c` and `lemon`.  Indeed such generators are available for non-C languages
+such as `alex` and `happy` for Haskell, or `PLY` for Python.
+
+Parsing Expression Grammars
+===========================
+
+[PEGs][] are a type of parser which typically end up represented as a
+[recursive descent][] parser.  PEGs sometimes allow for a parser to be
+represented in a way which is more natural for the language definer.  PEGs also
+have effectively got infinite look-ahead, allowing them to parse grammars which
+a more traditional `LALR(1)` would be unable to.
+
+Combinatory Parsing
+===================
+
+[Parser combinators][] take advantage of higher order functions in programming
+languages to allow a parser to be built up by combining smaller parsers
+together into more complex parsers, until a full parser for the input can be
+built.  The lowest level building blocks of such parsers are often called
+terminal recognisers and they recognise the smallest possible building block of
+the input (which could be a token from a lexical analyser or could be a byte or
+unicode character).  Most parser combinator libraries offer a number of
+standard combinators, such as one which will recognise one or more of the
+passed in parser, returning the recognised elements as a list.
+
+Sadly, due to the strong functional programming nature of combinators, it's
+often very hard to statically analyse the parser to check for ambiguities or
+inconsistencies in the grammar.  These issues only tend to become obvious at
+runtime, meaning that if you're using parser combinators to build your parser,
+it's recommended that you carefully write your grammar first, and convert it
+to code second.
+
+Homework
+========
+
+Find a program which you use, which consumes input in a form specific to the
+program itself.  (Or find a library which is meant to parse some format) and
+take a deep look at how it performs lexical analysis and parsing.
+
+
+[parsing]: https://en.wikipedia.org/wiki/Parsing
+[Lexical analysis]: https://en.wikipedia.org/wiki/Lexical_analysis
+[tokens]: https://en.wikipedia.org/wiki/Lexical_analysis#Token
+[abstract syntax tree]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
+[grammar]: https://en.wikipedia.org/wiki/Formal_grammar
+[LALR(1)]: https://en.wikipedia.org/wiki/LALR_parser
+[PEGs]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
+[recursive descent]: https://en.wikipedia.org/wiki/Recursive_descent_parser
+[Parser combinators]: https://en.wikipedia.org/wiki/Parser_combinator

Very braindumpy idea, not even sure if it should be published
diff --git a/drafts/kinnison-dead-or-resting.mdwn b/drafts/kinnison-dead-or-resting.mdwn
new file mode 100644
index 0000000..bd32007
--- /dev/null
+++ b/drafts/kinnison-dead-or-resting.mdwn
@@ -0,0 +1,52 @@
+[[!meta title="Is it dead, or is it just resting?"]]
+[[!meta author="Daniel Silverstone"]]
+
+There are any number of metrics, heuristics, entrail-reading techniques, etc
+which can be used to determine whether or not a project is "alive" for a
+variety of meanings of that word.  Depending on what you need to use a project
+for, you might need to make such an assessment and so this week I'd like to
+give you a few ways to assess a software project's "liveness".  In addition,
+you might be a project developer who needs to assess the "liveness" of
+something you're working on yourself. (For example to check it's well organised
+for your expected user-base).
+
+If you're trying to use a project in a production situation then you likely
+want to look to whether the codebase is relatively stable, whether it makes
+sensibly structured releases with some kind of semantic versioning, what its
+tracker looks like (relatively few open *BUGS*, short times between bug reports
+and fixes), and what its documentation looks like.  You may also look for
+evidence that others rely on the project, but that's perhaps less important.
+It's fine for the codebase to have a lot of churn providing there seems to be
+some commitment to a stable/reliable interface (be that a CLI or an API).
+
+If, on the other hand, you're looking for a project to use in a fairly
+experimental situation, you may be looking for a project whose developers are
+very active and responding well to feature requests, bug reports, etc, but
+where the number of open bugs is much less relevant than the way that the
+developers react to new uses of their codebase.
+
+If you're looking for a project to contribute to, then assuming you've already
+determined your own interest in the project to be high, I'd suggest that you
+look to how the developers/community, how active (or otherwise) they are, how
+well they respond to comments/queries/issues/bugs etc.  A project which is
+beautifully written but whose developers take months over responding to simple
+queries might not be suitable for you to join.  On the other hand, a nicely
+written project whose developers are essentially absent is very much ripe for
+an offer of adoption and/or simple forking.
+
+(As a corollary, if you're a project developer and someone turns up looking at
+your project and you know it's not right for them,
+[consider pointing them somewhere else](http://blog.petdance.com/2018/01/02/the-best-open-source-project-for-someone-might-not-be-yours-and-thats-ok/).)
+
+So, in summary, useful things to look at include:
+
+* The churn in the project codebase
+* Whether the project has adopted semantic versioning
+* Whether the project makes lots of bugfix releases or seems stable
+* How well the project team responds to new issues/bugs
+* How well the project accepts contributions.
+
+This week your homework is to assess a project you're part of, with the eyes of
+someone who might be coming to it to use/contribute-to.  See if you can find
+ways you could improve your own projects, and give it a go.
+

Add: draft on "when to retire"
diff --git a/drafts/liw-when-to-retire.mdwn b/drafts/liw-when-to-retire.mdwn
new file mode 100644
index 0000000..d2202cd
--- /dev/null
+++ b/drafts/liw-when-to-retire.mdwn
@@ -0,0 +1,31 @@
+[[!meta title="Knowing when to retire from a project"]]
+[[!meta author="Lars Wirzenius"]]
+
+A few months ago we published an article on
+[[how to retire|/posts/retiring/]]. It was followed by my decision to
+[retire Obnam](https://blog.liw.fi/posts/2017/08/13/retiring_obnam).
+Today, we will discuss how you know you should retire from a free
+software project.
+
+Here are some possible reasons:
+
+* It's no longer fun.
+* You no longer have time for it.
+* It's no longer a useful project.
+* It requires hardware you no longer have.
+* You don't like the technical decisions made in the project and
+  changing them now would be too much work.
+* The project has no users anymore.
+* You have a falling out with the other contributors.
+* You just don't want to work on the project anymore.
+* You win the lottery and can't be bothered to do anything anymore.
+* You become enlightened and realise that computers are preventing you
+  from becoming happy, so you give away everything you have, and move
+  into a cave to meditate.
+* The project is finished and requires no more work: it has all the
+  features its users need, and all bugs have been fixed.
+
+You may also like the talk [Consensually doing things together?][] by
+Enrico Zini from the 2017 Debconf.
+
+[Consensually doing things together?]: https://debconf17.debconf.org/talks/92/

Add: VM for development ideas
diff --git a/posts/ideas.mdwn b/posts/ideas.mdwn
index b61500f..5903750 100644
--- a/posts/ideas.mdwn
+++ b/posts/ideas.mdwn
@@ -1,5 +1,14 @@
 [[!meta title="Ideas for posts"]]
 
+* using virtual machines effectively for development
+    - types of VMs (chroot, container, qemu, kvm, virtualbox, vmware,
+      etc)
+    - types of VM management (libvirt, openstack, vagrant, etc)
+    - storage management (image file, lvm)
+    - managing VM configuration (ansible, vagrant, etc)
+    - sharing files betewen host and guest (9p, nfs, rsync, git)
+    - editing files remotely (remote editor, emacs tramp)
+    - ssh -A
 * starting your own project
     - source code layout
     - code hosting

publishing
diff --git a/queue/20180103-isolation.mdwn b/queue/20180103-isolation.mdwn
deleted file mode 100644
index fb8561c..0000000
--- a/queue/20180103-isolation.mdwn
+++ /dev/null
@@ -1,97 +0,0 @@
-[[!meta title="Isolation — when it's good to be alone…"]]
-[[!meta author="Daniel Silverstone"]]
-
-Today I'd like to talk to you about isolation.  Not, as some of you might
-expect given the topics of my more recent ramblings, about personal isolation -
-but about software isolation.
-
-Software isolation means different things to different people; from something
-as common as
-[process isolation](https://en.wikipedia.org/wiki/Process_isolation) which
-happens on almost every computing platform in the modern world, to something
-less common such virtual machines provided by
-[hypervisor](https://en.wikipedia.org/wiki/Hypervisor)s.  For today, let's
-focus on stuff closer to the latter than the former.
-
-Isolating software has, as in all things, both pros and cons.  Briefly, some of
-the reasons you might want to not consider software isolation may include:
-
-1. It's generally harder work to write software to be isolated easily.
-2. Each isolation point is "yet more" software which either has to be written
-   or at least has to be managed by your operations team.
-3. If you take a complex system, and distribute it among isolated systems, then
-   you have a more complex system than before.
-
-But, since I'm not going to be a
-[Danny Downer](https://en.wikipedia.org/wiki/Debbie_Downer) today, let's think
-more about the benefits.  Here are three benefits to counter the detractions
-I listed above.
-
-1. An isolated software system must have well defined inputs and outputs which
-   can be more effectively documented, mocked, and tested.  Leading to:
-    1. More easily tested and verified
-    2. Easier to debug
-    3. Easier to properly document
-2. An isolated software system cannot interfere indirectly with any other
-   software system sharing the same hardware or other infrastructure.
-3. A system comprised of multiple isolated intercommunicating software systems
-   can be more effectively distributed and thus horizontally scaled.
-
-There are any number of different ways to isolate your software systems from
-one another.  These range in "weight" and "completeness of isolation":
-
-* At the "lightest weight" end of things, we're looking at software written in
-  languages which support virtual environments.  This might be Python's
-  [venv](https://docs.python.org/3/library/venv.html), Ruby's
-  [rvm](https://rvm.io/), or something like
-  [luaenv](https://github.com/cehoffman/luaenv) for Lua.  These give you only
-  as much isolation as the language's virtual environment support extends to
-  (typically just for the dependencies provided in the language itself).
-
-* Next we might consider [chroot](https://en.wikipedia.org/wiki/Chroot)s which
-  give you filesystem isolation but very little else.  This lets you keep the
-  non-language-specific dependencies isolated too, since effectively a chroot
-  is able to be anything from "just enough to run your app" up to a full
-  install of the "user space" of your operating system.
-
-* Building from the `chroot` context, we can reach for a little more isolation
-  in the form of _containers_. On Linux, these can be managed by such tools as
-  [Docker](https://www.docker.com/), [LXC](https://linuxcontainers.org/),
-  [systemd-nspawn](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html),
-  or [rkt](https://coreos.com/rkt/).  This approach uses the Linux kernel
-  [namespacing facilities](https://en.wikipedia.org/wiki/Linux_namespaces) to
-  provide further isolation between containers than the above options can do.
-
-* If containers don't provide enough isolation for you, then you might proceed
-  to hypervisors such as [kvm](https://www.linux-kvm.org/page/Main_Page) via
-  [libvirt](https://libvirt.org/), or if you're in a desktop situation then
-  perhaps [virtualbox](https://www.virtualbox.org/).  There're plenty more
-  hypervisors out there though.  Hypervisors isolate at the "hardware" level.
-  They effectively provide independently operating virtual hardware elements in
-  the form of emulated hard drives, video cards, etc.  Such that the kernel and
-  underlying operating system run just as though they were on real hardware.
-
-* The final isolation option if not even hypervisors cut it for you, is, of
-  course, simply to have more than one computer and run each piece of your
-  software system on a different machine.
-
-There are any number of software packages out there to help you manage your
-isolated software environments.  From
-[schroot](https://wiki.debian.org/Schroot) for chroots, through the container
-providers linked above, and on to hypervisor options.  But what's even more
-exciting, as you start to think about scaling your software horizontally, is
-that there's also any number of providers out there offering services where
-they look after the hardware and the management layer, and you get to deploy
-isolated software elements onto their platform (usually for a fee).  These
-might be hypervisor based virtualisation on Amazon AWS, or any number of
-providers using [Openstack](https://www.openstack.org/).  Where it gets taken
-to the next level though is that those providers are starting to offer a range
-of isolation techniques, from containers upward, so whatever your needs, there
-will be software and providers out there to help you with software isolation.
-
-Your homework… (What?  You surely didn't think that just because it's a new
-year you wouldn't get any homework on the first day?) …is to think about any
-software systems you're responsible for, and whether they might benefit from
-having their elements isolated from one another more effectively, so that you
-might glean some of the benefits of isolation.
-

enqueue
diff --git a/drafts/kinnison-isolation.mdwn b/queue/20180103-isolation.mdwn
similarity index 100%
rename from drafts/kinnison-isolation.mdwn
rename to queue/20180103-isolation.mdwn

more tweaks
diff --git a/drafts/kinnison-isolation.mdwn b/drafts/kinnison-isolation.mdwn
index 5c5df1b..fb8561c 100644
--- a/drafts/kinnison-isolation.mdwn
+++ b/drafts/kinnison-isolation.mdwn
@@ -54,8 +54,8 @@ one another.  These range in "weight" and "completeness of isolation":
   is able to be anything from "just enough to run your app" up to a full
   install of the "user space" of your operating system.
 
-* Building from the `chroot` context we can reach for a little more isolation
-  in the form of _containers_ provided (at least on Linux) by such tools as
+* Building from the `chroot` context, we can reach for a little more isolation
+  in the form of _containers_. On Linux, these can be managed by such tools as
   [Docker](https://www.docker.com/), [LXC](https://linuxcontainers.org/),
   [systemd-nspawn](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html),
   or [rkt](https://coreos.com/rkt/).  This approach uses the Linux kernel

Semi-colon-tastic
diff --git a/drafts/kinnison-isolation.mdwn b/drafts/kinnison-isolation.mdwn
index 4f3fdfa..5c5df1b 100644
--- a/drafts/kinnison-isolation.mdwn
+++ b/drafts/kinnison-isolation.mdwn
@@ -5,7 +5,7 @@ Today I'd like to talk to you about isolation.  Not, as some of you might
 expect given the topics of my more recent ramblings, about personal isolation -
 but about software isolation.
 
-Software isolation means different things to different people, from something
+Software isolation means different things to different people; from something
 as common as
 [process isolation](https://en.wikipedia.org/wiki/Process_isolation) which
 happens on almost every computing platform in the modern world, to something

Fix fragment
diff --git a/drafts/kinnison-isolation.mdwn b/drafts/kinnison-isolation.mdwn
index 8df7454..4f3fdfa 100644
--- a/drafts/kinnison-isolation.mdwn
+++ b/drafts/kinnison-isolation.mdwn
@@ -49,7 +49,10 @@ one another.  These range in "weight" and "completeness of isolation":
   (typically just for the dependencies provided in the language itself).
 
 * Next we might consider [chroot](https://en.wikipedia.org/wiki/Chroot)s which
-  give you filesystem isolation but very little else.  This lets you k
+  give you filesystem isolation but very little else.  This lets you keep the
+  non-language-specific dependencies isolated too, since effectively a chroot
+  is able to be anything from "just enough to run your app" up to a full
+  install of the "user space" of your operating system.
 
 * Building from the `chroot` context we can reach for a little more isolation
   in the form of _containers_ provided (at least on Linux) by such tools as

Isolation, first draft
diff --git a/drafts/kinnison-isolation.mdwn b/drafts/kinnison-isolation.mdwn
new file mode 100644
index 0000000..8df7454
--- /dev/null
+++ b/drafts/kinnison-isolation.mdwn
@@ -0,0 +1,94 @@
+[[!meta title="Isolation — when it's good to be alone…"]]
+[[!meta author="Daniel Silverstone"]]
+
+Today I'd like to talk to you about isolation.  Not, as some of you might
+expect given the topics of my more recent ramblings, about personal isolation -
+but about software isolation.
+
+Software isolation means different things to different people, from something
+as common as
+[process isolation](https://en.wikipedia.org/wiki/Process_isolation) which
+happens on almost every computing platform in the modern world, to something
+less common such virtual machines provided by
+[hypervisor](https://en.wikipedia.org/wiki/Hypervisor)s.  For today, let's
+focus on stuff closer to the latter than the former.
+
+Isolating software has, as in all things, both pros and cons.  Briefly, some of
+the reasons you might want to not consider software isolation may include:
+
+1. It's generally harder work to write software to be isolated easily.
+2. Each isolation point is "yet more" software which either has to be written
+   or at least has to be managed by your operations team.
+3. If you take a complex system, and distribute it among isolated systems, then
+   you have a more complex system than before.
+
+But, since I'm not going to be a
+[Danny Downer](https://en.wikipedia.org/wiki/Debbie_Downer) today, let's think
+more about the benefits.  Here are three benefits to counter the detractions
+I listed above.
+
+1. An isolated software system must have well defined inputs and outputs which
+   can be more effectively documented, mocked, and tested.  Leading to:
+    1. More easily tested and verified
+    2. Easier to debug
+    3. Easier to properly document
+2. An isolated software system cannot interfere indirectly with any other
+   software system sharing the same hardware or other infrastructure.
+3. A system comprised of multiple isolated intercommunicating software systems
+   can be more effectively distributed and thus horizontally scaled.
+
+There are any number of different ways to isolate your software systems from
+one another.  These range in "weight" and "completeness of isolation":
+
+* At the "lightest weight" end of things, we're looking at software written in
+  languages which support virtual environments.  This might be Python's
+  [venv](https://docs.python.org/3/library/venv.html), Ruby's
+  [rvm](https://rvm.io/), or something like
+  [luaenv](https://github.com/cehoffman/luaenv) for Lua.  These give you only
+  as much isolation as the language's virtual environment support extends to
+  (typically just for the dependencies provided in the language itself).
+
+* Next we might consider [chroot](https://en.wikipedia.org/wiki/Chroot)s which
+  give you filesystem isolation but very little else.  This lets you k
+
+* Building from the `chroot` context we can reach for a little more isolation
+  in the form of _containers_ provided (at least on Linux) by such tools as
+  [Docker](https://www.docker.com/), [LXC](https://linuxcontainers.org/),
+  [systemd-nspawn](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html),
+  or [rkt](https://coreos.com/rkt/).  This approach uses the Linux kernel
+  [namespacing facilities](https://en.wikipedia.org/wiki/Linux_namespaces) to
+  provide further isolation between containers than the above options can do.
+
+* If containers don't provide enough isolation for you, then you might proceed
+  to hypervisors such as [kvm](https://www.linux-kvm.org/page/Main_Page) via
+  [libvirt](https://libvirt.org/), or if you're in a desktop situation then
+  perhaps [virtualbox](https://www.virtualbox.org/).  There're plenty more
+  hypervisors out there though.  Hypervisors isolate at the "hardware" level.
+  They effectively provide independently operating virtual hardware elements in
+  the form of emulated hard drives, video cards, etc.  Such that the kernel and
+  underlying operating system run just as though they were on real hardware.
+
+* The final isolation option if not even hypervisors cut it for you, is, of
+  course, simply to have more than one computer and run each piece of your
+  software system on a different machine.
+
+There are any number of software packages out there to help you manage your
+isolated software environments.  From
+[schroot](https://wiki.debian.org/Schroot) for chroots, through the container
+providers linked above, and on to hypervisor options.  But what's even more
+exciting, as you start to think about scaling your software horizontally, is
+that there's also any number of providers out there offering services where
+they look after the hardware and the management layer, and you get to deploy
+isolated software elements onto their platform (usually for a fee).  These
+might be hypervisor based virtualisation on Amazon AWS, or any number of
+providers using [Openstack](https://www.openstack.org/).  Where it gets taken
+to the next level though is that those providers are starting to offer a range
+of isolation techniques, from containers upward, so whatever your needs, there
+will be software and providers out there to help you with software isolation.
+
+Your homework… (What?  You surely didn't think that just because it's a new
+year you wouldn't get any homework on the first day?) …is to think about any
+software systems you're responsible for, and whether they might benefit from
+having their elements isolated from one another more effectively, so that you
+might glean some of the benefits of isolation.
+

Add: idea for articles
diff --git a/posts/ideas.mdwn b/posts/ideas.mdwn
index 828570f..b61500f 100644
--- a/posts/ideas.mdwn
+++ b/posts/ideas.mdwn
@@ -41,6 +41,14 @@
 * how to be a mensch, and help make the world better for those not white straight
   males
 * how to estimate the number of people who use your software
+* virtulisation options: qemu, kvm, libvirt, virtualbox, openstack,
+  aws, docker, lxc, systemd-nspawn, ...
+* stability of software vs adding tons of features all the time - pros
+  and cons of each approach
+* how to have a disagreement without burning bridges or ragequitting
+* Why Lua is the bestest language evah!
+* recognising WHEN to withdraw from a project or shutting it down
+
 
 # Ideas for short reserve articles
 

calendar update
diff --git a/archives/2018.mdwn b/archives/2018.mdwn
new file mode 100644
index 0000000..e62c64e
--- /dev/null
+++ b/archives/2018.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2018 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2018/01.mdwn b/archives/2018/01.mdwn
new file mode 100644
index 0000000..21c038d
--- /dev/null
+++ b/archives/2018/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/02.mdwn b/archives/2018/02.mdwn
new file mode 100644
index 0000000..e6db08f
--- /dev/null
+++ b/archives/2018/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/03.mdwn b/archives/2018/03.mdwn
new file mode 100644
index 0000000..3c67a9f
--- /dev/null
+++ b/archives/2018/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/04.mdwn b/archives/2018/04.mdwn
new file mode 100644
index 0000000..89e91b0
--- /dev/null
+++ b/archives/2018/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/05.mdwn b/archives/2018/05.mdwn
new file mode 100644
index 0000000..76556e2
--- /dev/null
+++ b/archives/2018/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/06.mdwn b/archives/2018/06.mdwn
new file mode 100644
index 0000000..7244cd0
--- /dev/null
+++ b/archives/2018/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/07.mdwn b/archives/2018/07.mdwn
new file mode 100644
index 0000000..b7659d6
--- /dev/null
+++ b/archives/2018/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/08.mdwn b/archives/2018/08.mdwn
new file mode 100644
index 0000000..2044f98
--- /dev/null
+++ b/archives/2018/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/09.mdwn b/archives/2018/09.mdwn
new file mode 100644
index 0000000..ed51cd6
--- /dev/null
+++ b/archives/2018/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/10.mdwn b/archives/2018/10.mdwn
new file mode 100644
index 0000000..f916789
--- /dev/null
+++ b/archives/2018/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/11.mdwn b/archives/2018/11.mdwn
new file mode 100644
index 0000000..253e46a
--- /dev/null
+++ b/archives/2018/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2018/12.mdwn b/archives/2018/12.mdwn
new file mode 100644
index 0000000..bc7c9c6
--- /dev/null
+++ b/archives/2018/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2018 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2018) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

publishing
diff --git a/queue/20171228-productivity-boosters.mdwn b/queue/20171228-productivity-boosters.mdwn
deleted file mode 100644
index 0fa96d4..0000000
--- a/queue/20171228-productivity-boosters.mdwn
+++ /dev/null
@@ -1,77 +0,0 @@
-[[!meta title="Programmer productivity boosters"]]
-[[!meta author="Lars Wirzenius"]]
-[[!tag productivity tools]]
-
-When I was young and has just started to learn programming, I read
-some descriptions of what programming was like as a job. These fell
-roughly into one of two categories:
-
-* long meetings, and writing a lot of documentation
-* long days of furious hacking fuelled by chemicals
-
-That was decades ago. I have since learn from experience that a
-programmer's productivity is best boosted by:
-
-* knowing clearly what to do
-  - a well-defined goal is easier to reach than one that is unclear or
-    changes all the time
-* knowing one's tools and being comfortable with them
-  - the exploration phase of using a new tool is rarely very productive
-* not being interrupted while doing it
-  - being in the [flow][] is commonly preferred, but may or may not be
-    necessary; however, frequent interruptions are anti-productive in
-    any case
-* getting enough sleep
-  - continuous yawning is distracting, concentration is difficult if
-    your brain is hallucinating from lack of sleep
-* avoidance of bad stress
-  - stress that makes you worry about the future is bad
-* having a reliable source of [lapsang][] tea
-  - but I need to stop drinking it at least six hours before bedtime,
-    or I sleep badly
-* a comfortable work environment
-  - see our [previous article][]
-
-It further helps to use various tools that allow the programmer
-concentrate on cranking out the code:
-
-* automated language checkers
-  - statically types languages require you to get types right, and
-    will catch you if you mistype a variable name
-  - static checkers for dynamically typed languages can often do the
-    same job
-  - either way, they help you catch errors earlier, which means you
-    spend less time waiting for an error to happen
-* automated tests
-  - unit tests, integration tests, etc, allow you to avoid spending
-    time and effort on doing the same tests manually over and over
-* reuse of high-quality code
-  - this means libraries, code generators, tools you can run, etc
-  - these save you time by not having to write the code yourself
-  - they further save time by not having to debug the code you wrote
-  - however, beware of low-quality code; it won't save you time, since
-    you'll almost certainly have to debug and fix it yourself
-* automated systems to run your automated tests
-  - [continuous integration][] runs without you having to remember to
-    run your tests
-  - it also runs them in the background, meaning you don't need to
-    wait for them to finish, which is especially useful when you have
-    slow tests
-  - the tests also get run in a well-defined environment, rather than
-    the developer's randomly configured ever-changing laptop
-* automated system for installing software on target machines
-  - [continuous delivery][] takes care of installing your software
-    somewhere you can use it, which may or may not be the production
-    server
-  - this is especially useful for server, web, and command line
-    software, but is generally useful
-  - often the process of installing manually is tedious - just like
-    doing manual testing - so the more it's automated the less time
-    you waste on repetitive work
-
-
-[Lapsang]: https://en.wikipedia.org/wiki/Lapsang_souchong
-[flow]: https://en.wikipedia.org/wiki/Flow_(psychology)
-[continuous integration]: https://en.wikipedia.org/wiki/Continuous_integration
-[continuous delivery]: https://en.wikipedia.org/wiki/Continuous_delivery
-[previous article]: https://yakking.branchable.com/posts/working-environment/

Queue: productivity booster
diff --git a/drafts/liw-boosters.mdwn b/queue/20171228-productivity-boosters.mdwn
similarity index 100%
rename from drafts/liw-boosters.mdwn
rename to queue/20171228-productivity-boosters.mdwn

Fix: wording about low-quality code
Thanks to Leslie.
diff --git a/drafts/liw-boosters.mdwn b/drafts/liw-boosters.mdwn
index 795fa61..0fa96d4 100644
--- a/drafts/liw-boosters.mdwn
+++ b/drafts/liw-boosters.mdwn
@@ -49,8 +49,8 @@ concentrate on cranking out the code:
   - this means libraries, code generators, tools you can run, etc
   - these save you time by not having to write the code yourself
   - they further save time by not having to debug the code you wrote
-  - low-quality code doesn't save you time, since you'll have to debug
-    and fix it yourself
+  - however, beware of low-quality code; it won't save you time, since
+    you'll almost certainly have to debug and fix it yourself
 * automated systems to run your automated tests
   - [continuous integration][] runs without you having to remember to
     run your tests

Add: link to Daniel's work env article
diff --git a/drafts/liw-boosters.mdwn b/drafts/liw-boosters.mdwn
index cb8e657..795fa61 100644
--- a/drafts/liw-boosters.mdwn
+++ b/drafts/liw-boosters.mdwn
@@ -29,6 +29,8 @@ programmer's productivity is best boosted by:
 * having a reliable source of [lapsang][] tea
   - but I need to stop drinking it at least six hours before bedtime,
     or I sleep badly
+* a comfortable work environment
+  - see our [previous article][]
 
 It further helps to use various tools that allow the programmer
 concentrate on cranking out the code:
@@ -72,3 +74,4 @@ concentrate on cranking out the code:
 [flow]: https://en.wikipedia.org/wiki/Flow_(psychology)
 [continuous integration]: https://en.wikipedia.org/wiki/Continuous_integration
 [continuous delivery]: https://en.wikipedia.org/wiki/Continuous_delivery
+[previous article]: https://yakking.branchable.com/posts/working-environment/

Fix: spellos, missing flow link
diff --git a/drafts/liw-boosters.mdwn b/drafts/liw-boosters.mdwn
index d432496..cb8e657 100644
--- a/drafts/liw-boosters.mdwn
+++ b/drafts/liw-boosters.mdwn
@@ -16,7 +16,7 @@ programmer's productivity is best boosted by:
   - a well-defined goal is easier to reach than one that is unclear or
     changes all the time
 * knowing one's tools and being comfortable with them
-  - the exploration phase of using a new tool is rarly very productive
+  - the exploration phase of using a new tool is rarely very productive
 * not being interrupted while doing it
   - being in the [flow][] is commonly preferred, but may or may not be
     necessary; however, frequent interruptions are anti-productive in
@@ -65,9 +65,10 @@ concentrate on cranking out the code:
     software, but is generally useful
   - often the process of installing manually is tedious - just like
     doing manual testing - so the more it's automated the less time
-    you waste on repetive work
+    you waste on repetitive work
 
 
 [Lapsang]: https://en.wikipedia.org/wiki/Lapsang_souchong
+[flow]: https://en.wikipedia.org/wiki/Flow_(psychology)
 [continuous integration]: https://en.wikipedia.org/wiki/Continuous_integration
 [continuous delivery]: https://en.wikipedia.org/wiki/Continuous_delivery

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

Add: draft of productivity booster article
diff --git a/drafts/liw-boosters.mdwn b/drafts/liw-boosters.mdwn
new file mode 100644
index 0000000..d432496
--- /dev/null
+++ b/drafts/liw-boosters.mdwn
@@ -0,0 +1,73 @@
+[[!meta title="Programmer productivity boosters"]]
+[[!meta author="Lars Wirzenius"]]
+[[!tag productivity tools]]
+
+When I was young and has just started to learn programming, I read
+some descriptions of what programming was like as a job. These fell
+roughly into one of two categories:
+
+* long meetings, and writing a lot of documentation
+* long days of furious hacking fuelled by chemicals
+
+That was decades ago. I have since learn from experience that a
+programmer's productivity is best boosted by:
+
+* knowing clearly what to do
+  - a well-defined goal is easier to reach than one that is unclear or
+    changes all the time
+* knowing one's tools and being comfortable with them
+  - the exploration phase of using a new tool is rarly very productive
+* not being interrupted while doing it
+  - being in the [flow][] is commonly preferred, but may or may not be
+    necessary; however, frequent interruptions are anti-productive in
+    any case
+* getting enough sleep
+  - continuous yawning is distracting, concentration is difficult if
+    your brain is hallucinating from lack of sleep
+* avoidance of bad stress
+  - stress that makes you worry about the future is bad
+* having a reliable source of [lapsang][] tea
+  - but I need to stop drinking it at least six hours before bedtime,
+    or I sleep badly
+
+It further helps to use various tools that allow the programmer
+concentrate on cranking out the code:
+
+* automated language checkers
+  - statically types languages require you to get types right, and
+    will catch you if you mistype a variable name
+  - static checkers for dynamically typed languages can often do the
+    same job
+  - either way, they help you catch errors earlier, which means you
+    spend less time waiting for an error to happen
+* automated tests
+  - unit tests, integration tests, etc, allow you to avoid spending
+    time and effort on doing the same tests manually over and over
+* reuse of high-quality code
+  - this means libraries, code generators, tools you can run, etc
+  - these save you time by not having to write the code yourself
+  - they further save time by not having to debug the code you wrote
+  - low-quality code doesn't save you time, since you'll have to debug
+    and fix it yourself
+* automated systems to run your automated tests
+  - [continuous integration][] runs without you having to remember to
+    run your tests
+  - it also runs them in the background, meaning you don't need to
+    wait for them to finish, which is especially useful when you have
+    slow tests
+  - the tests also get run in a well-defined environment, rather than
+    the developer's randomly configured ever-changing laptop
+* automated system for installing software on target machines
+  - [continuous delivery][] takes care of installing your software
+    somewhere you can use it, which may or may not be the production
+    server
+  - this is especially useful for server, web, and command line
+    software, but is generally useful
+  - often the process of installing manually is tedious - just like
+    doing manual testing - so the more it's automated the less time
+    you waste on repetive work
+
+
+[Lapsang]: https://en.wikipedia.org/wiki/Lapsang_souchong
+[continuous integration]: https://en.wikipedia.org/wiki/Continuous_integration
+[continuous delivery]: https://en.wikipedia.org/wiki/Continuous_delivery

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

queue
diff --git a/drafts/kinnison-working-environment.mdwn b/queue/20171213-working-environment.mdwn
similarity index 100%
rename from drafts/kinnison-working-environment.mdwn
rename to queue/20171213-working-environment.mdwn

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

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

(Diff truncated)
fix a typo
diff --git a/queue/20171206-property-testing-in-c.mdwn b/queue/20171206-property-testing-in-c.mdwn
index 834f5e6..f27f581 100644
--- a/queue/20171206-property-testing-in-c.mdwn
+++ b/queue/20171206-property-testing-in-c.mdwn
@@ -125,7 +125,7 @@ function returns with `THEFT_ALLOC_OK`. In the event of some kind of
 error the function should return `THEFT_ALLOC_ERROR`
 
 Next we write the property function, this function takes an input
-array of integers generated by Theft, runs our `even` function over that input and
+array of integers generated by Theft, runs our `evens` function over that input and
 asserts that the resultant output doesn't contain any odd numbers.
 
 [[!format c """

Missing includes
diff --git a/queue/20171206-property-testing-in-c.mdwn b/queue/20171206-property-testing-in-c.mdwn
index 352223d..834f5e6 100644
--- a/queue/20171206-property-testing-in-c.mdwn
+++ b/queue/20171206-property-testing-in-c.mdwn
@@ -36,6 +36,8 @@ Let's reimplement our Haskell code in C,
 
 [[!format c """
 #include <stdio.h>
+#include <stdlib.h>
+#include <theft.h>
 
 struct IntArray {
     int len;

Simple fix
diff --git a/queue/20171206-property-testing-in-c.mdwn b/queue/20171206-property-testing-in-c.mdwn
index 8d2663b..352223d 100644
--- a/queue/20171206-property-testing-in-c.mdwn
+++ b/queue/20171206-property-testing-in-c.mdwn
@@ -189,7 +189,7 @@ int main(void)
         .seed = seed
     };
 
-    return theft_run(&config) == THEFT_RUN_PASS;
+    return (theft_run(&config) == THEFT_RUN_PASS) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 """]]
 

retitle
diff --git a/queue/20171206-property-testing-in-c.mdwn b/queue/20171206-property-testing-in-c.mdwn
index 1640e3c..8d2663b 100644
--- a/queue/20171206-property-testing-in-c.mdwn
+++ b/queue/20171206-property-testing-in-c.mdwn
@@ -1,4 +1,4 @@
-[[!meta title="Theft, And Wandering Around Lost (or Property Testing in C)"]]
+[[!meta title="Property Testing in C"]]
 [[!meta author="Richard Ipsum"]]
 
 One nice thing about [Haskell][] is [Quickcheck][], if you're not familiar with

enqueue
diff --git a/drafts/ripsum-property-testing-in-c.mdwn b/queue/20171206-property-testing-in-c.mdwn
similarity index 100%
rename from drafts/ripsum-property-testing-in-c.mdwn
rename to queue/20171206-property-testing-in-c.mdwn

Add missing line
diff --git a/drafts/ripsum-property-testing-in-c.mdwn b/drafts/ripsum-property-testing-in-c.mdwn
index 4638ab9..1640e3c 100644
--- a/drafts/ripsum-property-testing-in-c.mdwn
+++ b/drafts/ripsum-property-testing-in-c.mdwn
@@ -201,6 +201,7 @@ Compiling and running:
     == PROP 'main': 100 trials, seed 0x62a401b7fa52ac8b
     .......................................................................
     .............................
+    == PASS 'main': pass 100, fail 0, skip 0, dup 0
 
 I hope this helps anyone looking to try out Property Testing in C.
 Another guide that might be useful can be found [here](https://spin.atomicobject.com/2014/09/17/property-based-testing-c/),

move link to property testing
diff --git a/drafts/ripsum-property-testing-in-c.mdwn b/drafts/ripsum-property-testing-in-c.mdwn
index c732545..4638ab9 100644
--- a/drafts/ripsum-property-testing-in-c.mdwn
+++ b/drafts/ripsum-property-testing-in-c.mdwn
@@ -1,9 +1,8 @@
 [[!meta title="Theft, And Wandering Around Lost (or Property Testing in C)"]]
 [[!meta author="Richard Ipsum"]]
 
-Today we're going to be talking about [Property Testing][] in the C language,
-but first a digression: One nice thing about [Haskell][] is [Quickcheck][], if
-you're not familiar with Haskell or Quickcheck it works like this:
+One nice thing about [Haskell][] is [Quickcheck][], if you're not familiar with
+Haskell or Quickcheck it works like this:
 
 [[!format haskell """
 Prelude> let evens xs = [ x | x <- xs, x `mod` 2 == 0 ]
@@ -31,7 +30,7 @@ with those inputs.
 Clearly this type of testing can be very useful, and not just for
 Haskell programs. [Theft](https://github.com/silentbicycle/theft) is a C
 library that brings Quickcheck style testing to C. This sort of testing
-is known as Property Testing.
+is known as [Property Testing][].
 
 Let's reimplement our Haskell code in C,
 

Add a quick note at the top about property testing
diff --git a/drafts/ripsum-property-testing-in-c.mdwn b/drafts/ripsum-property-testing-in-c.mdwn
index a435832..c732545 100644
--- a/drafts/ripsum-property-testing-in-c.mdwn
+++ b/drafts/ripsum-property-testing-in-c.mdwn
@@ -1,8 +1,9 @@
 [[!meta title="Theft, And Wandering Around Lost (or Property Testing in C)"]]
 [[!meta author="Richard Ipsum"]]
 
-One nice thing about [Haskell][] is [Quickcheck][], if you're not familiar with
-Haskell or Quickcheck it works like this:
+Today we're going to be talking about [Property Testing][] in the C language,
+but first a digression: One nice thing about [Haskell][] is [Quickcheck][], if
+you're not familiar with Haskell or Quickcheck it works like this:
 
 [[!format haskell """
 Prelude> let evens xs = [ x | x <- xs, x `mod` 2 == 0 ]
@@ -209,3 +210,4 @@ be useful for more complex situations.
 
 [Haskell]: https://www.haskell.org/
 [Quickcheck]: https://hackage.haskell.org/package/QuickCheck
+[Property Testing]: https://en.wikipedia.org/wiki/Property_testing

Link Haskell and Quickcheck
diff --git a/drafts/ripsum-property-testing-in-c.mdwn b/drafts/ripsum-property-testing-in-c.mdwn
index 7aea62c..a435832 100644
--- a/drafts/ripsum-property-testing-in-c.mdwn
+++ b/drafts/ripsum-property-testing-in-c.mdwn
@@ -1,7 +1,7 @@
 [[!meta title="Theft, And Wandering Around Lost (or Property Testing in C)"]]
 [[!meta author="Richard Ipsum"]]
 
-One nice thing about Haskell is Quickcheck, if you're not familiar with
+One nice thing about [Haskell][] is [Quickcheck][], if you're not familiar with
 Haskell or Quickcheck it works like this:
 
 [[!format haskell """
@@ -206,3 +206,6 @@ I hope this helps anyone looking to try out Property Testing in C.
 Another guide that might be useful can be found [here](https://spin.atomicobject.com/2014/09/17/property-based-testing-c/),
 it has an example that uses a manually defined shrinking function, which may
 be useful for more complex situations.
+
+[Haskell]: https://www.haskell.org/
+[Quickcheck]: https://hackage.haskell.org/package/QuickCheck