summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--TOUR.722
-rw-r--r--agpl.c3
-rw-r--r--bin/.gitignore1
-rw-r--r--bin/Makefile2
-rw-r--r--bin/README.74
-rw-r--r--bin/beef.c7
-rw-r--r--bin/bit.y3
-rw-r--r--bin/c11.l2
-rw-r--r--bin/dehtml.l7
-rw-r--r--bin/downgrade.c57
-rw-r--r--bin/dtch.c61
-rw-r--r--bin/ever.c23
-rw-r--r--bin/freecell.c5
-rw-r--r--bin/git-comment.pl2
-rw-r--r--bin/glitch.c694
-rw-r--r--bin/hilex.c29
-rw-r--r--bin/hilex.h2
-rw-r--r--bin/htagml.c23
-rw-r--r--bin/make.l2
-rw-r--r--bin/man1/qf.171
-rw-r--r--bin/man1/up.118
-rw-r--r--bin/man1/when.134
-rw-r--r--bin/mdoc.l2
-rw-r--r--bin/modem.c29
-rw-r--r--bin/mtags.c11
-rw-r--r--bin/nudge.c15
-rw-r--r--bin/order.y11
-rw-r--r--bin/pbd.c45
-rw-r--r--bin/png.h5
-rw-r--r--bin/pngo.c85
-rw-r--r--bin/psf2png.c17
-rw-r--r--bin/ptee.c39
-rw-r--r--bin/qf.c293
-rw-r--r--bin/quick.c21
-rw-r--r--bin/relay.c45
-rw-r--r--bin/scheme.c7
-rw-r--r--bin/sh.l14
-rw-r--r--bin/shotty.l15
-rw-r--r--bin/title.c19
-rw-r--r--bin/up.sh30
-rw-r--r--bin/when.y134
-rw-r--r--bin/xx.c15
-rw-r--r--doc/pdf/.gitignore1
-rw-r--r--doc/pdf/Makefile31
-rw-r--r--doc/zlib/adler32.32
-rw-r--r--doc/zlib/adler32_combine.32
-rw-r--r--doc/zlib/compress.32
-rw-r--r--doc/zlib/compressBound.32
-rw-r--r--doc/zlib/crc32.32
-rw-r--r--doc/zlib/crc32_combine.32
-rw-r--r--doc/zlib/deflate.32
-rw-r--r--doc/zlib/deflateBound.32
-rw-r--r--doc/zlib/deflateCopy.32
-rw-r--r--doc/zlib/deflateEnd.32
-rw-r--r--doc/zlib/deflateGetDictionary.32
-rw-r--r--doc/zlib/deflateInit.32
-rw-r--r--doc/zlib/deflateInit2.32
-rw-r--r--doc/zlib/deflateParams.32
-rw-r--r--doc/zlib/deflatePending.32
-rw-r--r--doc/zlib/deflatePrime.32
-rw-r--r--doc/zlib/deflateReset.32
-rw-r--r--doc/zlib/deflateSetDictionary.32
-rw-r--r--doc/zlib/deflateSetHeader.32
-rw-r--r--doc/zlib/deflateTune.32
-rw-r--r--doc/zlib/gzbuffer.32
-rw-r--r--doc/zlib/gzclose.32
-rw-r--r--doc/zlib/gzdirect.32
-rw-r--r--doc/zlib/gzeof.32
-rw-r--r--doc/zlib/gzerror.32
-rw-r--r--doc/zlib/gzflush.32
-rw-r--r--doc/zlib/gzfread.32
-rw-r--r--doc/zlib/gzfwrite.32
-rw-r--r--doc/zlib/gzgetc.32
-rw-r--r--doc/zlib/gzgets.32
-rw-r--r--doc/zlib/gzoffset.32
-rw-r--r--doc/zlib/gzopen.32
-rw-r--r--doc/zlib/gzprintf.32
-rw-r--r--doc/zlib/gzputc.32
-rw-r--r--doc/zlib/gzputs.32
-rw-r--r--doc/zlib/gzread.32
-rw-r--r--doc/zlib/gzseek.32
-rw-r--r--doc/zlib/gzsetparams.32
-rw-r--r--doc/zlib/gzungetc.32
-rw-r--r--doc/zlib/gzwrite.32
-rw-r--r--doc/zlib/inflate.32
-rw-r--r--doc/zlib/inflateBack.32
-rw-r--r--doc/zlib/inflateBackEnd.32
-rw-r--r--doc/zlib/inflateBackInit.32
-rw-r--r--doc/zlib/inflateCopy.32
-rw-r--r--doc/zlib/inflateEnd.32
-rw-r--r--doc/zlib/inflateGetDictionary.32
-rw-r--r--doc/zlib/inflateGetHeader.32
-rw-r--r--doc/zlib/inflateInit.32
-rw-r--r--doc/zlib/inflateInit2.32
-rw-r--r--doc/zlib/inflateMark.32
-rw-r--r--doc/zlib/inflatePrime.32
-rw-r--r--doc/zlib/inflateReset.32
-rw-r--r--doc/zlib/inflateSetDictionary.32
-rw-r--r--doc/zlib/inflateSync.32
-rw-r--r--doc/zlib/uncompress.32
-rw-r--r--doc/zlib/zlibCompileFlags.32
-rw-r--r--doc/zlib/zlibVersion.32
-rw-r--r--gpl.c3
-rw-r--r--home/.config/X/resources2
-rw-r--r--home/.config/git/config9
-rwxr-xr-xhome/.local/bin/mins4
-rw-r--r--home/.shrc16
-rw-r--r--home/.ssh/config9
-rw-r--r--home/.xsession7
-rw-r--r--install.sh2
-rw-r--r--txt/books.txt30
-rw-r--r--txt/shows.txt3
-rw-r--r--txt/tweets.txt32
-rw-r--r--www/causal.agency/.gitignore3
-rw-r--r--www/causal.agency/Makefile11
-rw-r--r--www/causal.agency/alpha.html92
-rw-r--r--www/causal.agency/index.724
-rw-r--r--www/causal.agency/lands.html176
-rw-r--r--www/causal.agency/style.css5
-rw-r--r--www/git.causal.agency/.gitignore1
-rw-r--r--www/git.causal.agency/Makefile11
-rw-r--r--www/git.causal.agency/filter.c10
-rw-r--r--www/git.causal.agency/index.781
-rw-r--r--www/photo.causal.agency/.gitignore6
-rw-r--r--www/photo.causal.agency/0062/body1
-rw-r--r--www/photo.causal.agency/0062/date1
-rw-r--r--www/photo.causal.agency/0062/film1
-rw-r--r--www/photo.causal.agency/0062/lens1
-rw-r--r--www/photo.causal.agency/0063/body1
-rw-r--r--www/photo.causal.agency/0063/date1
-rw-r--r--www/photo.causal.agency/0063/film1
-rw-r--r--www/photo.causal.agency/0063/lens1
-rw-r--r--www/photo.causal.agency/0064/body1
-rw-r--r--www/photo.causal.agency/0064/date1
-rw-r--r--www/photo.causal.agency/0064/film1
-rw-r--r--www/photo.causal.agency/0064/lens1
-rw-r--r--www/photo.causal.agency/0065/body1
-rw-r--r--www/photo.causal.agency/0065/date1
-rw-r--r--www/photo.causal.agency/0065/film1
-rw-r--r--www/photo.causal.agency/0065/lens1
-rw-r--r--www/photo.causal.agency/0066/body1
-rw-r--r--www/photo.causal.agency/0066/date1
-rw-r--r--www/photo.causal.agency/0066/film1
-rw-r--r--www/photo.causal.agency/0066/lens1
-rw-r--r--www/photo.causal.agency/0067/body1
-rw-r--r--www/photo.causal.agency/0067/date1
-rw-r--r--www/photo.causal.agency/0067/film1
-rw-r--r--www/photo.causal.agency/0067/lens1
-rw-r--r--www/photo.causal.agency/0068/body1
-rw-r--r--www/photo.causal.agency/0068/date1
-rw-r--r--www/photo.causal.agency/0068/film1
-rw-r--r--www/photo.causal.agency/0068/lens1
-rw-r--r--www/photo.causal.agency/0069/body1
-rw-r--r--www/photo.causal.agency/0069/date1
-rw-r--r--www/photo.causal.agency/0069/film1
-rw-r--r--www/photo.causal.agency/0069/lens1
-rw-r--r--www/photo.causal.agency/0070/body1
-rw-r--r--www/photo.causal.agency/0070/date1
-rw-r--r--www/photo.causal.agency/0070/film1
-rw-r--r--www/photo.causal.agency/0070/lens1
-rw-r--r--www/photo.causal.agency/0071/body1
-rw-r--r--www/photo.causal.agency/0071/date1
-rw-r--r--www/photo.causal.agency/0071/film1
-rw-r--r--www/photo.causal.agency/0071/lens1
-rw-r--r--www/photo.causal.agency/0072/body1
-rw-r--r--www/photo.causal.agency/0072/date1
-rw-r--r--www/photo.causal.agency/0072/film1
-rw-r--r--www/photo.causal.agency/0072/lens1
-rw-r--r--www/photo.causal.agency/0073/body1
-rw-r--r--www/photo.causal.agency/0073/date1
-rw-r--r--www/photo.causal.agency/0073/film1
-rw-r--r--www/photo.causal.agency/0073/lens1
-rw-r--r--www/photo.causal.agency/0074/body1
-rw-r--r--www/photo.causal.agency/0074/date1
-rw-r--r--www/photo.causal.agency/0074/film1
-rw-r--r--www/photo.causal.agency/0074/lens1
-rw-r--r--www/photo.causal.agency/0075/body1
-rw-r--r--www/photo.causal.agency/0075/date1
-rw-r--r--www/photo.causal.agency/0075/film1
-rw-r--r--www/photo.causal.agency/0075/lens1
-rw-r--r--www/photo.causal.agency/0076/body1
-rw-r--r--www/photo.causal.agency/0076/date1
-rw-r--r--www/photo.causal.agency/0076/film1
-rw-r--r--www/photo.causal.agency/0076/lens1
-rw-r--r--www/photo.causal.agency/0077/body1
-rw-r--r--www/photo.causal.agency/0077/date1
-rw-r--r--www/photo.causal.agency/0077/film1
-rw-r--r--www/photo.causal.agency/0077/lens1
-rw-r--r--www/photo.causal.agency/0078/body1
-rw-r--r--www/photo.causal.agency/0078/date1
-rw-r--r--www/photo.causal.agency/0078/film1
-rw-r--r--www/photo.causal.agency/0078/lens1
-rw-r--r--www/photo.causal.agency/0079/body1
-rw-r--r--www/photo.causal.agency/0079/date1
-rw-r--r--www/photo.causal.agency/0079/film1
-rw-r--r--www/photo.causal.agency/0079/lens1
-rw-r--r--www/photo.causal.agency/0080/body1
-rw-r--r--www/photo.causal.agency/0080/date1
-rw-r--r--www/photo.causal.agency/0080/film1
-rw-r--r--www/photo.causal.agency/0080/lens1
-rw-r--r--www/photo.causal.agency/0080/note3
-rw-r--r--www/photo.causal.agency/2024-04-10/IMG_0832.txt6
-rw-r--r--www/photo.causal.agency/2024-04-10/IMG_0850.txt6
-rw-r--r--www/photo.causal.agency/2024-04-10/IMG_0852.txt4
-rw-r--r--www/photo.causal.agency/2024-04-10/IMG_0858.txt6
-rw-r--r--www/photo.causal.agency/2024-04-10/IMG_0859.txt6
-rw-r--r--www/photo.causal.agency/2024-04-10/IMG_0865.txt2
-rw-r--r--www/photo.causal.agency/2024-04-10/IMG_0890.txt9
-rw-r--r--www/photo.causal.agency/2024-04-14/IMG_1054.txt5
-rw-r--r--www/photo.causal.agency/2024-04-14/IMG_1058.txt6
-rw-r--r--www/photo.causal.agency/2024-04-14/IMG_1066.txt10
-rw-r--r--www/photo.causal.agency/2024-04-19/IMG_1158.txt6
-rw-r--r--www/photo.causal.agency/2024-04-20/IMG_1225.txt8
-rw-r--r--www/photo.causal.agency/2024-04-20/IMG_1234.txt8
-rw-r--r--www/photo.causal.agency/2024-04-20/IMG_1245.txt17
-rw-r--r--www/photo.causal.agency/2024-04-20/IMG_1253.txt7
-rw-r--r--www/photo.causal.agency/2024-04-20/IMG_1254.txt8
-rw-r--r--www/photo.causal.agency/2024-04-30/IMG_1619.txt8
-rw-r--r--www/photo.causal.agency/2024-05-03/IMG_1684.txt7
-rw-r--r--www/photo.causal.agency/2024-05-03/IMG_1692.txt4
-rw-r--r--www/photo.causal.agency/2024-05-03/IMG_1706.txt4
-rw-r--r--www/photo.causal.agency/2024-05-03/IMG_1724.txt3
-rw-r--r--www/photo.causal.agency/2024-05-03/IMG_1730.txt9
-rw-r--r--www/photo.causal.agency/2024-05-03/IMG_1748.txt4
-rw-r--r--www/photo.causal.agency/2024-05-06/IMG_1951.txt12
-rw-r--r--www/photo.causal.agency/2024-05-06/IMG_1969.txt7
-rw-r--r--www/photo.causal.agency/2024-05-06/IMG_1973.txt3
-rw-r--r--www/photo.causal.agency/2024-05-06/IMG_1996.txt4
-rw-r--r--www/photo.causal.agency/2024-05-06/IMG_1998.txt3
-rw-r--r--www/photo.causal.agency/2024-05-06/IMG_2009.txt4
-rw-r--r--www/photo.causal.agency/2024-05-06/IMG_2015.txt4
-rw-r--r--www/photo.causal.agency/2024-05-31/IMG_2078.txt5
-rw-r--r--www/photo.causal.agency/2024-05-31/IMG_2079.txt7
-rw-r--r--www/photo.causal.agency/2024-05-31/IMG_2084.txt4
-rw-r--r--www/photo.causal.agency/2024-05-31/IMG_2103.txt8
-rw-r--r--www/photo.causal.agency/2024-05-31/IMG_2114.txt6
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-009A.txt9
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-011A.txt6
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-012A.txt9
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-015A.txt6
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-016A.txt5
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-020A.txt12
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-024A.txt5
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-026A.txt2
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-028A.txt5
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-030A.txt7
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-031A.txt7
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-032A.txt7
-rw-r--r--www/photo.causal.agency/2024-06-08/R1-07534-036A.txt12
-rw-r--r--www/photo.causal.agency/2024-06-08/film1
-rw-r--r--www/photo.causal.agency/2024-06-08/lens1
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-002A.txt14
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-003A.txt6
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-007A.txt5
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-009A.txt7
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-010A.txt8
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-012A.txt3
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-013A.txt7
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-015A.txt4
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-016A.txt4
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-029A.txt4
-rw-r--r--www/photo.causal.agency/2024-06-12/R1-07671-031A.txt4
-rw-r--r--www/photo.causal.agency/2024-06-12/film1
-rw-r--r--www/photo.causal.agency/2024-06-12/lens1
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910004.txt5
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910008.txt3
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910009.txt7
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910014.txt4
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910015.txt4
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910016.txt2
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910017.txt3
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910019.txt5
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910021.txt6
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910022.txt4
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910023.txt4
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910026.txt10
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910027.txt2
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910031.txt3
-rw-r--r--www/photo.causal.agency/2024-06-22/000093910032.txt10
-rw-r--r--www/photo.causal.agency/2024-06-22/film1
-rw-r--r--www/photo.causal.agency/2024-06-22/lens1
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820005.txt8
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820006.txt7
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820008.txt9
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820010.txt9
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820011.txt10
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820012.txt3
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820013.txt7
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820018.txt5
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820019.txt2
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820022.txt4
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820023.txt3
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820026.txt3
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820029.txt3
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820033.txt3
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820035.txt7
-rw-r--r--www/photo.causal.agency/2024-06-25/000099820038.txt5
-rw-r--r--www/photo.causal.agency/2024-06-25/film1
-rw-r--r--www/photo.causal.agency/2024-06-25/lens1
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800001.txt11
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800002.txt4
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800007.txt4
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800008.txt4
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800011.txt3
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800017.txt2
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800020.txt7
-rw-r--r--www/photo.causal.agency/2024-07-01/000099800021.txt4
-rw-r--r--www/photo.causal.agency/2024-07-01/film1
-rw-r--r--www/photo.causal.agency/2024-07-01/lens1
-rw-r--r--www/photo.causal.agency/2024-07-03/000099800022.txt6
-rw-r--r--www/photo.causal.agency/2024-07-03/000099800023.txt4
-rw-r--r--www/photo.causal.agency/2024-07-03/000099800032.txt9
-rw-r--r--www/photo.causal.agency/2024-07-03/000099800036.txt3
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810001.txt4
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810002.txt4
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810008.txt3
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810013.txt6
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810014.txt7
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810017.txt6
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810019.txt5
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810021.txt4
-rw-r--r--www/photo.causal.agency/2024-07-03/000099810022.txt4
-rw-r--r--www/photo.causal.agency/2024-07-03/film1
-rw-r--r--www/photo.causal.agency/2024-07-03/lens1
-rw-r--r--www/photo.causal.agency/2024-07-04/000099810029.txt6
-rw-r--r--www/photo.causal.agency/2024-07-04/000099810033.txt6
-rw-r--r--www/photo.causal.agency/2024-07-04/000099810036.txt2
-rw-r--r--www/photo.causal.agency/2024-07-04/film1
-rw-r--r--www/photo.causal.agency/2024-07-04/lens1
-rw-r--r--www/photo.causal.agency/2024-07-06/000005110004.txt8
-rw-r--r--www/photo.causal.agency/2024-07-06/000005110005.txt5
-rw-r--r--www/photo.causal.agency/2024-07-06/000005110012.txt3
-rw-r--r--www/photo.causal.agency/2024-07-06/000005110013.txt7
-rw-r--r--www/photo.causal.agency/2024-07-06/000005110014.txt3
-rw-r--r--www/photo.causal.agency/2024-07-06/000005110017.txt2
-rw-r--r--www/photo.causal.agency/2024-07-06/film1
-rw-r--r--www/photo.causal.agency/2024-07-06/lens1
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110025.txt5
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110026.txt8
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110028.txt3
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110029.txt9
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110030.txt5
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110033.txt6
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110035.txt6
-rw-r--r--www/photo.causal.agency/2024-07-09/000005110036.txt8
-rw-r--r--www/photo.causal.agency/2024-07-09/film1
-rw-r--r--www/photo.causal.agency/2024-07-09/lens1
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180002.txt3
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180006.txt10
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180010.txt8
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180014.txt3
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180020.txt11
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180023.txt5
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180025.txt6
-rw-r--r--www/photo.causal.agency/2024-07-14/000009180028.txt3
-rw-r--r--www/photo.causal.agency/2024-07-14/film1
-rw-r--r--www/photo.causal.agency/2024-07-14/lens1
-rw-r--r--www/photo.causal.agency/2024-07-27/000025480003.txt5
-rw-r--r--www/photo.causal.agency/2024-07-27/000025480009.txt2
-rw-r--r--www/photo.causal.agency/2024-07-27/000025480010.txt5
-rw-r--r--www/photo.causal.agency/2024-07-27/000025480012.txt7
-rw-r--r--www/photo.causal.agency/2024-07-27/film1
-rw-r--r--www/photo.causal.agency/2024-07-27/lens1
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480014.txt3
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480017.txt5
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480018.txt5
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480028.txt11
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480030.txt21
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480033.txt7
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480034.txt8
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480035.txt7
-rw-r--r--www/photo.causal.agency/2024-07-29/000025480036.txt15
-rw-r--r--www/photo.causal.agency/2024-07-29/film1
-rw-r--r--www/photo.causal.agency/2024-07-29/lens1
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490001.txt2
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490002.txt4
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490003.txt2
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490004.txt6
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490009.txt4
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490010.txt3
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490012.txt5
-rw-r--r--www/photo.causal.agency/2024-07-30/000025490014.txt5
-rw-r--r--www/photo.causal.agency/2024-07-30/film1
-rw-r--r--www/photo.causal.agency/2024-07-30/lens1
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490019.txt5
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490026.txt5
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490027.txt6
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490029.txt6
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490030.txt5
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490031.txt4
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490035.txt7
-rw-r--r--www/photo.causal.agency/2024-08-02/000025490036.txt11
-rw-r--r--www/photo.causal.agency/2024-08-02/film1
-rw-r--r--www/photo.causal.agency/2024-08-02/lens1
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420002.txt5
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420005.txt4
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420007.txt3
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420011.txt2
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420012.txt4
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420015.txt4
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420016.txt8
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420020.txt2
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420024.txt3
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420026.txt3
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420027.txt8
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420028.txt2
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420029.txt3
-rw-r--r--www/photo.causal.agency/2024-08-10/000031420034.txt4
-rw-r--r--www/photo.causal.agency/2024-08-10/body1
-rw-r--r--www/photo.causal.agency/2024-08-10/film1
-rw-r--r--www/photo.causal.agency/2024-08-10/lens1
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750004.txt2
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750007.txt7
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750008.txt3
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750009.txt2
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750010.txt3
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750013.txt5
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750014.txt8
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750016.txt7
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750024.txt6
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750027.txt5
-rw-r--r--www/photo.causal.agency/2024-08-22/000044750028.txt3
-rw-r--r--www/photo.causal.agency/2024-08-22/body1
-rw-r--r--www/photo.causal.agency/2024-08-22/film1
-rw-r--r--www/photo.causal.agency/2024-08-22/lens1
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740001.txt8
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740002.txt5
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740010.txt5
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740014.txt4
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740017.txt2
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740021.txt5
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740024.txt8
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740030.txt8
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740031.txt4
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740033.txt6
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740034.txt6
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740035.txt4
-rw-r--r--www/photo.causal.agency/2024-08-23/000044740036.txt14
-rw-r--r--www/photo.causal.agency/2024-08-23/body1
-rw-r--r--www/photo.causal.agency/2024-08-23/film1
-rw-r--r--www/photo.causal.agency/2024-08-23/lens1
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730001.txt6
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730002.txt4
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730004.txt5
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730008.txt6
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730012.txt3
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730014.txt3
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730018.txt4
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730026.txt8
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730028.txt2
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730029.txt2
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730030.txt1
-rw-r--r--www/photo.causal.agency/2024-08-24/000044730035.txt4
-rw-r--r--www/photo.causal.agency/2024-08-24/body1
-rw-r--r--www/photo.causal.agency/2024-08-24/film1
-rw-r--r--www/photo.causal.agency/2024-08-24/lens1
-rw-r--r--www/photo.causal.agency/2024-08-29/000054970002.txt3
-rw-r--r--www/photo.causal.agency/2024-08-29/000054970004.txt5
-rw-r--r--www/photo.causal.agency/2024-08-29/body1
-rw-r--r--www/photo.causal.agency/2024-08-29/film1
-rw-r--r--www/photo.causal.agency/2024-08-29/lens1
-rw-r--r--www/photo.causal.agency/2024-09-02/000054970017.txt11
-rw-r--r--www/photo.causal.agency/2024-09-02/000054970018.txt7
-rw-r--r--www/photo.causal.agency/2024-09-02/000054970019.txt6
-rw-r--r--www/photo.causal.agency/2024-09-02/000054970021.txt11
-rw-r--r--www/photo.causal.agency/2024-09-02/000054970022.txt3
-rw-r--r--www/photo.causal.agency/2024-09-02/000054970023.txt3
-rw-r--r--www/photo.causal.agency/2024-09-02/000054970029.txt6
-rw-r--r--www/photo.causal.agency/2024-09-02/body1
-rw-r--r--www/photo.causal.agency/2024-09-02/film1
-rw-r--r--www/photo.causal.agency/2024-09-02/lens1
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000003.txt6
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000009.txt5
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000010.txt3
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000014.txt4
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000017.txt4
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000018.txt5
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000023.txt5
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000024.txt5
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000025.txt5
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000026.txt4
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000027.txt3
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000032.txt4
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000033.txt4
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000038.txt4
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000042.txt3
-rw-r--r--www/photo.causal.agency/2024-09-05/06124000044.txt8
-rw-r--r--www/photo.causal.agency/2024-09-05/body1
-rw-r--r--www/photo.causal.agency/2024-09-05/film1
-rw-r--r--www/photo.causal.agency/2024-09-05/lens1
-rw-r--r--www/photo.causal.agency/2024-09-07/body1
-rw-r--r--www/photo.causal.agency/2024-09-07/film1
-rw-r--r--www/photo.causal.agency/2024-09-07/lens1
-rw-r--r--www/photo.causal.agency/2024-09-12/body1
-rw-r--r--www/photo.causal.agency/2024-09-12/film1
-rw-r--r--www/photo.causal.agency/2024-09-12/lens1
-rw-r--r--www/photo.causal.agency/2024-09-14/body1
-rw-r--r--www/photo.causal.agency/2024-09-14/film1
-rw-r--r--www/photo.causal.agency/2024-09-14/lens1
-rw-r--r--www/photo.causal.agency/2024-09-15/body1
-rw-r--r--www/photo.causal.agency/2024-09-15/film1
-rw-r--r--www/photo.causal.agency/2024-09-15/lens1
-rw-r--r--www/photo.causal.agency/2024-09-22/body1
-rw-r--r--www/photo.causal.agency/2024-09-22/film1
-rw-r--r--www/photo.causal.agency/2024-09-22/lens1
-rw-r--r--www/photo.causal.agency/2024-09-28/body1
-rw-r--r--www/photo.causal.agency/2024-09-28/film1
-rw-r--r--www/photo.causal.agency/2024-09-28/lens1
-rw-r--r--www/photo.causal.agency/2024-09-29/body1
-rw-r--r--www/photo.causal.agency/2024-09-29/film1
-rw-r--r--www/photo.causal.agency/2024-09-29/lens1
-rw-r--r--www/photo.causal.agency/2024-10-01/body1
-rw-r--r--www/photo.causal.agency/2024-10-01/film1
-rw-r--r--www/photo.causal.agency/2024-10-01/lens1
-rw-r--r--www/photo.causal.agency/2024-10-05/body1
-rw-r--r--www/photo.causal.agency/2024-10-05/film1
-rw-r--r--www/photo.causal.agency/2024-10-05/lens1
-rw-r--r--www/photo.causal.agency/2024-10-06/body1
-rw-r--r--www/photo.causal.agency/2024-10-06/film1
-rw-r--r--www/photo.causal.agency/2024-10-06/lens1
-rw-r--r--www/photo.causal.agency/2024-10-12/body1
-rw-r--r--www/photo.causal.agency/2024-10-12/film1
-rw-r--r--www/photo.causal.agency/2024-10-12/lens1
-rw-r--r--www/photo.causal.agency/2024-10-17/body1
-rw-r--r--www/photo.causal.agency/2024-10-17/film1
-rw-r--r--www/photo.causal.agency/2024-10-17/lens1
-rw-r--r--www/photo.causal.agency/2024-10-20/body1
-rw-r--r--www/photo.causal.agency/2024-10-20/film1
-rw-r--r--www/photo.causal.agency/2024-10-20/lens1
-rw-r--r--www/photo.causal.agency/2024-10-23/body1
-rw-r--r--www/photo.causal.agency/2024-10-23/film1
-rw-r--r--www/photo.causal.agency/2024-10-23/lens1
-rw-r--r--www/photo.causal.agency/2024-10-27/body1
-rw-r--r--www/photo.causal.agency/2024-10-27/film1
-rw-r--r--www/photo.causal.agency/2024-10-27/lens1
-rw-r--r--www/photo.causal.agency/2024-11-02/body1
-rw-r--r--www/photo.causal.agency/2024-11-02/film1
-rw-r--r--www/photo.causal.agency/2024-11-02/lens1
-rw-r--r--www/photo.causal.agency/2024-11-06/body1
-rw-r--r--www/photo.causal.agency/2024-11-06/film1
-rw-r--r--www/photo.causal.agency/2024-11-06/lens1
-rw-r--r--www/photo.causal.agency/2024-11-09/body1
-rw-r--r--www/photo.causal.agency/2024-11-09/film1
-rw-r--r--www/photo.causal.agency/2024-11-09/lens1
-rw-r--r--www/photo.causal.agency/2024-11-12/body1
-rw-r--r--www/photo.causal.agency/2024-11-12/film1
-rw-r--r--www/photo.causal.agency/2024-11-12/lens1
-rw-r--r--www/photo.causal.agency/2024-11-16/body1
-rw-r--r--www/photo.causal.agency/2024-11-16/film1
-rw-r--r--www/photo.causal.agency/2024-11-16/lens1
-rw-r--r--www/photo.causal.agency/2024-11-18/body1
-rw-r--r--www/photo.causal.agency/2024-11-18/film1
-rw-r--r--www/photo.causal.agency/2024-11-18/lens1
-rw-r--r--www/photo.causal.agency/2024-11-23/body1
-rw-r--r--www/photo.causal.agency/2024-11-23/film1
-rw-r--r--www/photo.causal.agency/2024-11-23/lens1
-rw-r--r--www/photo.causal.agency/2024-12-21/body1
-rw-r--r--www/photo.causal.agency/2024-12-21/film1
-rw-r--r--www/photo.causal.agency/2024-12-21/lens1
-rw-r--r--www/photo.causal.agency/2024-12-28/body1
-rw-r--r--www/photo.causal.agency/2024-12-28/film1
-rw-r--r--www/photo.causal.agency/2024-12-28/lens1
-rw-r--r--www/photo.causal.agency/2025-01-18/body1
-rw-r--r--www/photo.causal.agency/2025-01-18/film1
-rw-r--r--www/photo.causal.agency/2025-01-18/lens1
-rw-r--r--www/photo.causal.agency/2025-01-26/body1
-rw-r--r--www/photo.causal.agency/2025-01-26/film1
-rw-r--r--www/photo.causal.agency/2025-01-26/lens1
-rw-r--r--www/photo.causal.agency/2025-02-08/body1
-rw-r--r--www/photo.causal.agency/2025-02-08/film1
-rw-r--r--www/photo.causal.agency/2025-02-08/lens1
-rw-r--r--www/photo.causal.agency/2025-02-11/body1
-rw-r--r--www/photo.causal.agency/2025-02-11/film1
-rw-r--r--www/photo.causal.agency/2025-02-11/lens1
-rw-r--r--www/photo.causal.agency/2025-02-17/body1
-rw-r--r--www/photo.causal.agency/2025-02-17/film1
-rw-r--r--www/photo.causal.agency/2025-02-17/lens1
-rw-r--r--www/photo.causal.agency/2025-02-23/body1
-rw-r--r--www/photo.causal.agency/2025-02-23/film1
-rw-r--r--www/photo.causal.agency/2025-02-23/lens1
-rw-r--r--www/photo.causal.agency/2025-02-25/body1
-rw-r--r--www/photo.causal.agency/2025-02-25/film1
-rw-r--r--www/photo.causal.agency/2025-02-25/lens1
-rw-r--r--www/photo.causal.agency/2025-03-15/body1
-rw-r--r--www/photo.causal.agency/2025-03-15/film1
-rw-r--r--www/photo.causal.agency/2025-03-15/lens1
-rw-r--r--www/photo.causal.agency/2025-03-16/body1
-rw-r--r--www/photo.causal.agency/2025-03-16/film1
-rw-r--r--www/photo.causal.agency/2025-03-16/lens1
-rw-r--r--www/photo.causal.agency/2025-03-18/body1
-rw-r--r--www/photo.causal.agency/2025-03-18/film1
-rw-r--r--www/photo.causal.agency/2025-03-18/lens1
-rw-r--r--www/photo.causal.agency/2025-03-19/body1
-rw-r--r--www/photo.causal.agency/2025-03-19/film1
-rw-r--r--www/photo.causal.agency/2025-03-19/lens1
-rw-r--r--www/photo.causal.agency/2025-03-22/body1
-rw-r--r--www/photo.causal.agency/2025-03-22/film1
-rw-r--r--www/photo.causal.agency/2025-03-22/lens1
-rw-r--r--www/photo.causal.agency/2025-03-23/body1
-rw-r--r--www/photo.causal.agency/2025-03-23/film1
-rw-r--r--www/photo.causal.agency/2025-03-23/lens1
-rw-r--r--www/photo.causal.agency/c35/body1
-rw-r--r--www/photo.causal.agency/c35/lens1
-rw-r--r--www/photo.causal.agency/fx-3/body1
-rw-r--r--www/photo.causal.agency/fx-3/lens1
-rw-r--r--www/photo.causal.agency/gear.html65
-rw-r--r--www/photo.causal.agency/generate.sh284
-rw-r--r--www/photo.causal.agency/mastodon.sh54
-rw-r--r--www/photo.causal.agency/rsync.sh5
-rw-r--r--www/photo.causal.agency/trips.html365
-rw-r--r--www/temp.causal.agency/up.c2
-rw-r--r--www/text.causal.agency/037-care.762
-rw-r--r--www/text.causal.agency/039-apologies.781
-rw-r--r--www/text.causal.agency/040-sound-memory.7165
-rw-r--r--www/text.causal.agency/041-albums-2022.7185
-rw-r--r--www/text.causal.agency/042-comfort-music.762
-rw-r--r--www/text.causal.agency/043-little-blessings.778
-rw-r--r--www/text.causal.agency/044-film-review.7208
-rw-r--r--www/text.causal.agency/Makefile12
-rw-r--r--www/text.causal.agency/feed.sh1
620 files changed, 4904 insertions, 901 deletions
diff --git a/TOUR.7 b/TOUR.7
deleted file mode 100644
index 8466f524..00000000
--- a/TOUR.7
+++ /dev/null
@@ -1,22 +0,0 @@
-.Dd March 16, 2022
-.Dt TOUR 7
-.Os "Causal Agency"
-.
-.Sh NAME
-.Nm tour
-.Nd things that are here
-.
-.Sh FILES
-.Bl -tag -width Ds
-.It Pa home/
-.Dq dotfiles
-.It Pa bin/
-utilities of varying utility
-.It Pa doc/rfc/
-scripts for reading IETF RFCs
-.It Pa doc/zlib/
-zlib documentation ported to
-.Xr mdoc 7
-.It Pa www/
-sources for causal.agency sites
-.El
diff --git a/agpl.c b/agpl.c
index 58a88fc4..e7682757 100644
--- a/agpl.c
+++ b/agpl.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2022  June McEnroe <june@causal.agency>
+/* Copyright (C) 2024  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -17,4 +17,3 @@
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
diff --git a/bin/.gitignore b/bin/.gitignore
index 59b60826..42269bac 100644
--- a/bin/.gitignore
+++ b/bin/.gitignore
@@ -24,6 +24,7 @@ pbd
 pngo
 psf2png
 ptee
+qf
 quick
 relay
 scheme
diff --git a/bin/Makefile b/bin/Makefile
index 5d23ab3c..bb1535d6 100644
--- a/bin/Makefile
+++ b/bin/Makefile
@@ -26,6 +26,7 @@ BINS += pbd
 BINS += pngo
 BINS += psf2png
 BINS += ptee
+BINS += qf
 BINS += quick
 BINS += scheme
 BINS += shotty
@@ -55,6 +56,7 @@ LDLIBS.glitch = -lz
 LDLIBS.modem = -lutil
 LDLIBS.pngo = -lz
 LDLIBS.ptee = -lutil
+LDLIBS.qf = -lcurses
 LDLIBS.relay = -ltls
 LDLIBS.scheme = -lm
 LDLIBS.title = -lcurl
diff --git a/bin/README.7 b/bin/README.7
index c562e84c..100e183e 100644
--- a/bin/README.7
+++ b/bin/README.7
@@ -1,4 +1,4 @@
-.Dd January 30, 2022
+.Dd June  2, 2022
 .Dt BIN 7
 .Os "Causal Agency"
 .
@@ -58,6 +58,8 @@ PNG optimizer
 PSF2 to PNG renderer
 .It Xr ptee 1
 tee for PTYs
+.It Xr qf 1
+grep pager
 .It Xr quick 1
 terrible HTTP/CGI server
 .It Xr relay 1
diff --git a/bin/beef.c b/bin/beef.c
index b2579b73..31781753 100644
--- a/bin/beef.c
+++ b/bin/beef.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -19,7 +19,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <time.h>
 
 enum {
@@ -44,7 +43,7 @@ static long stack[StackLen];
 static size_t top = StackLen;
 
 static void push(long val) {
-	if (!top) errx(EX_SOFTWARE, "stack overflow");
+	if (!top) errx(1, "stack overflow");
 	stack[--top] = val;
 }
 static long pop(void) {
@@ -121,7 +120,7 @@ int main(int argc, char *argv[]) {
 	FILE *file = stdin;
 	if (argc > 1) {
 		file = fopen(argv[1], "r");
-		if (!file) err(EX_NOINPUT, "%s", argv[1]);
+		if (!file) err(1, "%s", argv[1]);
 	}
 
 	int y = 0;
diff --git a/bin/bit.y b/bin/bit.y
index ab310492..33f5f940 100644
--- a/bin/bit.y
+++ b/bin/bit.y
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -22,7 +22,6 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
 
 #define MASK(b) ((1ULL << (b)) - 1)
 
diff --git a/bin/c11.l b/bin/c11.l
index a4b8c25a..b1f0b960 100644
--- a/bin/c11.l
+++ b/bin/c11.l
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
diff --git a/bin/dehtml.l b/bin/dehtml.l
index 3f2de592..b6aa4eb8 100644
--- a/bin/dehtml.l
+++ b/bin/dehtml.l
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -47,7 +47,6 @@ enum Token {
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
-#include <sysexits.h>
 #include <unistd.h>
 #include <wchar.h>
 
@@ -107,7 +106,7 @@ int main(int argc, char *argv[]) {
 	for (int opt; 0 < (opt = getopt(argc, argv, "s"));) {
 		switch (opt) {
 			break; case 's': collapse = true;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 	argc -= optind;
@@ -116,7 +115,7 @@ int main(int argc, char *argv[]) {
 	if (!argc) argc++;
 	for (int i = 0; i < argc; ++i) {
 		yyin = (argv[i] ? fopen(argv[i], "r") : stdin);
-		if (!yyin) err(EX_NOINPUT, "%s", argv[i]);
+		if (!yyin) err(1, "%s", argv[i]);
 
 		bool space = true;
 		bool discard = false;
diff --git a/bin/downgrade.c b/bin/downgrade.c
index d4c5b598..0d76c787 100644
--- a/bin/downgrade.c
+++ b/bin/downgrade.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <tls.h>
 #include <unistd.h>
 
@@ -40,7 +39,7 @@ static void clientWrite(const char *ptr, size_t len) {
 	while (len) {
 		ssize_t ret = tls_write(client, ptr, len);
 		if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue;
-		if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(client));
+		if (ret < 0) errx(1, "tls_write: %s", tls_error(client));
 		ptr += ret;
 		len -= ret;
 	}
@@ -77,11 +76,11 @@ static void push(struct Message msg) {
 	dst->id = strdup(msg.id);
 	dst->nick = strdup(msg.nick);
 	dst->chan = strdup(msg.chan);
-	if (!dst->id || !dst->nick || !dst->chan) err(EX_OSERR, "strdup");
+	if (!dst->id || !dst->nick || !dst->chan) err(1, "strdup");
 	dst->mesg = NULL;
 	if (msg.mesg) {
 		dst->mesg = strdup(msg.mesg);
-		if (!dst->mesg) err(EX_OSERR, "strdup");
+		if (!dst->mesg) err(1, "strdup");
 	}
 }
 
@@ -103,11 +102,11 @@ static void handle(char *ptr) {
 	if (!strcmp(cmd, "CAP")) {
 		strsep(&ptr, " ");
 		char *sub = strsep(&ptr, " ");
-		if (!sub) errx(EX_PROTOCOL, "CAP without subcommand");
+		if (!sub) errx(1, "CAP without subcommand");
 		if (!strcmp(sub, "NAK")) {
-			errx(EX_CONFIG, "server does not support %s", ptr);
+			errx(1, "server does not support %s", ptr);
 		} else if (!strcmp(sub, "ACK")) {
-			if (!ptr) errx(EX_PROTOCOL, "CAP ACK without caps");
+			if (!ptr) errx(1, "CAP ACK without caps");
 			if (*ptr == ':') ptr++;
 			if (!strcmp(ptr, "sasl")) format("AUTHENTICATE EXTERNAL\r\n");
 		}
@@ -116,13 +115,13 @@ static void handle(char *ptr) {
 	} else if (!strcmp(cmd, "433")) {
 		strsep(&ptr, " ");
 		char *nick = strsep(&ptr, " ");
-		if (!nick) errx(EX_PROTOCOL, "ERR_NICKNAMEINUSE missing nick");
+		if (!nick) errx(1, "ERR_NICKNAMEINUSE missing nick");
 		format("NICK %s_\r\n", nick);
 	} else if (!strcmp(cmd, "001")) {
 		if (join) format("JOIN %s\r\n", join);
 	} else if (!strcmp(cmd, "005")) {
 		char *self = strsep(&ptr, " ");
-		if (!self) errx(EX_PROTOCOL, "RPL_ISUPPORT missing nick");
+		if (!self) errx(1, "RPL_ISUPPORT missing nick");
 		while (ptr && *ptr != ':') {
 			char *tok = strsep(&ptr, " ");
 			char *key = strsep(&tok, "=");
@@ -132,16 +131,16 @@ static void handle(char *ptr) {
 		}
 	} else if (!strcmp(cmd, "INVITE") && invite) {
 		strsep(&ptr, " ");
-		if (!ptr) errx(EX_PROTOCOL, "INVITE missing channel");
+		if (!ptr) errx(1, "INVITE missing channel");
 		if (*ptr == ':') ptr++;
 		format("JOIN %s\r\n", ptr);
 	} else if (!strcmp(cmd, "PING")) {
-		if (!ptr) errx(EX_PROTOCOL, "PING missing parameter");
+		if (!ptr) errx(1, "PING missing parameter");
 		format("PONG %s\r\n", ptr);
 	} else if (!strcmp(cmd, "ERROR")) {
-		if (!ptr) errx(EX_PROTOCOL, "ERROR missing parameter");
+		if (!ptr) errx(1, "ERROR missing parameter");
 		if (*ptr == ':') ptr++;
-		errx(EX_UNAVAILABLE, "%s", ptr);
+		errx(1, "%s", ptr);
 	}
 
 	if (
@@ -149,13 +148,13 @@ static void handle(char *ptr) {
 		strcmp(cmd, "NOTICE") &&
 		strcmp(cmd, "TAGMSG")
 	) return;
-	if (!origin) errx(EX_PROTOCOL, "%s missing origin", cmd);
+	if (!origin) errx(1, "%s missing origin", cmd);
 
 	struct Message msg = {
 		.nick = strsep(&origin, "!"),
 		.chan = strsep(&ptr, " "),
 	};
-	if (!msg.chan) errx(EX_PROTOCOL, "%s missing target", cmd);
+	if (!msg.chan) errx(1, "%s missing target", cmd);
 	if (msg.chan[0] == ':') msg.chan++;
 	if (msg.chan[0] != '#') return;
 	if (strcmp(cmd, "TAGMSG")) msg.mesg = (*ptr == ':' ? &ptr[1] : ptr);
@@ -263,7 +262,7 @@ static void quit(int sig) {
 	(void)sig;
 	format("QUIT\r\n");
 	tls_close(client);
-	exit(EX_OK);
+	exit(0);
 }
 
 int main(int argc, char *argv[]) {
@@ -282,44 +281,44 @@ int main(int argc, char *argv[]) {
 			break; case 'n': nick = optarg;
 			break; case 'p': port = optarg;
 			break; case 'v': verbose = true;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
-	if (optind == argc) errx(EX_USAGE, "host required");
+	if (optind == argc) errx(1, "host required");
 	host = argv[optind];
 
 	client = tls_client();
-	if (!client) errx(EX_SOFTWARE, "tls_client");
+	if (!client) errx(1, "tls_client");
 
 	struct tls_config *config = tls_config_new();
-	if (!config) errx(EX_SOFTWARE, "tls_config_new");
+	if (!config) errx(1, "tls_config_new");
 
 	if (cert) {
 		if (!priv) priv = cert;
 		int error = tls_config_set_keypair_file(config, cert, priv);
-		if (error) errx(EX_NOINPUT, "%s: %s", cert, tls_config_error(config));
+		if (error) errx(1, "%s: %s", cert, tls_config_error(config));
 	}
 
 	int error = tls_configure(client, config);
-	if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client));
+	if (error) errx(1, "tls_configure: %s", tls_error(client));
 
 	error = tls_connect(client, host, port);
-	if (error) errx(EX_UNAVAILABLE, "tls_connect: %s", tls_error(client));
+	if (error) errx(1, "tls_connect: %s", tls_error(client));
 
 	do {
 		error = tls_handshake(client);
 	} while (error == TLS_WANT_POLLIN || error == TLS_WANT_POLLOUT);
-	if (error) errx(EX_PROTOCOL, "tls_handshake: %s", tls_error(client));
+	if (error) errx(1, "tls_handshake: %s", tls_error(client));
 	tls_config_clear_keys(config);
 
 #ifdef __OpenBSD__
 	error = pledge("stdio", NULL);
-	if (error) err(EX_OSERR, "pledge");
+	if (error) err(1, "pledge");
 #endif
 
 #ifdef __FreeBSD__
 	error = caph_enter() || caph_limit_stdio();
-	if (error) err(EX_OSERR, "caph_enter");
+	if (error) err(1, "caph_enter");
 #endif
 
 	signal(SIGHUP, quit);
@@ -342,8 +341,8 @@ int main(int argc, char *argv[]) {
 	for (;;) {
 		ssize_t n = tls_read(client, &buf[len], sizeof(buf) - len);
 		if (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT) continue;
-		if (n < 0) errx(EX_IOERR, "tls_read: %s", tls_error(client));
-		if (!n) errx(EX_UNAVAILABLE, "disconnected");
+		if (n < 0) errx(1, "tls_read: %s", tls_error(client));
+		if (!n) errx(1, "disconnected");
 		len += n;
 
 		char *ptr = buf;
diff --git a/bin/dtch.c b/bin/dtch.c
index 2aea53ae..55b33910 100644
--- a/bin/dtch.c
+++ b/bin/dtch.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017-2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2017-2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -28,7 +28,6 @@
 #include <sys/stat.h>
 #include <sys/un.h>
 #include <sys/wait.h>
-#include <sysexits.h>
 #include <termios.h>
 #include <unistd.h>
 
@@ -91,18 +90,18 @@ static void handler(int sig) {
 static void detach(int server, bool sink, char *argv[]) {
 	int pty;
 	pid_t pid = forkpty(&pty, NULL, NULL, NULL);
-	if (pid < 0) err(EX_OSERR, "forkpty");
+	if (pid < 0) err(1, "forkpty");
 
 	if (!pid) {
 		execvp(argv[0], argv);
-		err(EX_NOINPUT, "%s", argv[0]);
+		err(127, "%s", argv[0]);
 	}
 
 	signal(SIGINT, handler);
 	signal(SIGTERM, handler);
 
 	int error = listen(server, 0);
-	if (error) err(EX_OSERR, "listen");
+	if (error) err(1, "listen");
 
 	struct pollfd fds[] = {
 		{ .events = POLLIN, .fd = server },
@@ -111,7 +110,7 @@ static void detach(int server, bool sink, char *argv[]) {
 	while (0 < poll(fds, (sink ? 2 : 1), -1)) {
 		if (fds[0].revents) {
 			int client = accept(server, NULL, NULL);
-			if (client < 0) err(EX_IOERR, "accept");
+			if (client < 0) err(1, "accept");
 
 			ssize_t len = sendfd(client, pty);
 			if (len < 0) warn("sendfd");
@@ -125,18 +124,18 @@ static void detach(int server, bool sink, char *argv[]) {
 		if (fds[1].revents) {
 			char buf[4096];
 			ssize_t len = read(pty, buf, sizeof(buf));
-			if (len < 0) err(EX_IOERR, "read");
+			if (len < 0) err(1, "read");
 		}
 
 		int status;
 		pid_t dead = waitpid(pid, &status, WNOHANG);
-		if (dead < 0) err(EX_OSERR, "waitpid");
+		if (dead < 0) err(1, "waitpid");
 		if (dead) {
 			unlink(addr.sun_path);
 			exit(WIFEXITED(status) ? WEXITSTATUS(status) : -WTERMSIG(status));
 		}
 	}
-	err(EX_IOERR, "poll");
+	err(1, "poll");
 }
 
 static struct termios saveTerm;
@@ -154,28 +153,28 @@ static void attach(int client) {
 	int error;
 
 	int pty = recvfd(client);
-	if (pty < 0) err(EX_IOERR, "recvfd");
+	if (pty < 0) err(1, "recvfd");
 	warnx("attached");
 
 	struct winsize window;
 	error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window);
-	if (error) err(EX_IOERR, "ioctl");
+	if (error) err(1, "ioctl");
 
 	struct winsize redraw = { .ws_row = 1, .ws_col = 1 };
 	error = ioctl(pty, TIOCSWINSZ, &redraw);
-	if (error) err(EX_IOERR, "ioctl");
+	if (error) err(1, "ioctl");
 
 	error = ioctl(pty, TIOCSWINSZ, &window);
-	if (error) err(EX_IOERR, "ioctl");
+	if (error) err(1, "ioctl");
 
 	error = tcgetattr(STDIN_FILENO, &saveTerm);
-	if (error) err(EX_IOERR, "tcgetattr");
+	if (error) err(1, "tcgetattr");
 	atexit(restoreTerm);
 
 	struct termios raw = saveTerm;
 	cfmakeraw(&raw);
 	error = tcsetattr(STDIN_FILENO, TCSADRAIN, &raw);
-	if (error) err(EX_IOERR, "tcsetattr");
+	if (error) err(1, "tcsetattr");
 
 	signal(SIGWINCH, nop);
 
@@ -187,35 +186,35 @@ static void attach(int client) {
 	for (;;) {
 		int nfds = poll(fds, 2, -1);
 		if (nfds < 0) {
-			if (errno != EINTR) err(EX_IOERR, "poll");
+			if (errno != EINTR) err(1, "poll");
 
 			error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window);
-			if (error) err(EX_IOERR, "ioctl");
+			if (error) err(1, "ioctl");
 
 			error = ioctl(pty, TIOCSWINSZ, &window);
-			if (error) err(EX_IOERR, "ioctl");
+			if (error) err(1, "ioctl");
 
 			continue;
 		}
 
 		if (fds[0].revents) {
 			ssize_t len = read(STDIN_FILENO, buf, sizeof(buf));
-			if (len < 0) err(EX_IOERR, "read");
+			if (len < 0) err(1, "read");
 			if (!len) break;
 
 			if (len == 1 && buf[0] == CTRL('Q')) break;
 
 			len = write(pty, buf, len);
-			if (len < 0) err(EX_IOERR, "write");
+			if (len < 0) err(1, "write");
 		}
 
 		if (fds[1].revents) {
 			ssize_t len = read(pty, buf, sizeof(buf));
-			if (len < 0) err(EX_IOERR, "read");
+			if (len < 0) err(1, "read");
 			if (!len) break;
 
 			len = write(STDOUT_FILENO, buf, len);
-			if (len < 0) err(EX_IOERR, "write");
+			if (len < 0) err(1, "write");
 		}
 	}
 }
@@ -231,41 +230,41 @@ int main(int argc, char *argv[]) {
 		switch (opt) {
 			break; case 'a': atch = true;
 			break; case 's': sink = true;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
-	if (optind == argc) errx(EX_USAGE, "no session name");
+	if (optind == argc) errx(1, "no session name");
 	const char *name = argv[optind++];
 
 	if (optind == argc) {
 		argv[--optind] = getenv("SHELL");
-		if (!argv[optind]) errx(EX_CONFIG, "SHELL unset");
+		if (!argv[optind]) errx(1, "SHELL unset");
 	}
 
 	const char *home = getenv("HOME");
-	if (!home) errx(EX_CONFIG, "HOME unset");
+	if (!home) errx(1, "HOME unset");
 
 	int fd = open(home, 0);
-	if (fd < 0) err(EX_CANTCREAT, "%s", home);
+	if (fd < 0) err(1, "%s", home);
 
 	error = mkdirat(fd, ".dtch", 0700);
-	if (error && errno != EEXIST) err(EX_CANTCREAT, "%s/.dtch", home);
+	if (error && errno != EEXIST) err(1, "%s/.dtch", home);
 
 	close(fd);
 
 	int sock = socket(PF_UNIX, SOCK_STREAM, 0);
-	if (sock < 0) err(EX_OSERR, "socket");
+	if (sock < 0) err(1, "socket");
 	fcntl(sock, F_SETFD, FD_CLOEXEC);
 
 	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.dtch/%s", home, name);
 
 	if (atch) {
 		error = connect(sock, (struct sockaddr *)&addr, SUN_LEN(&addr));
-		if (error) err(EX_NOINPUT, "%s", addr.sun_path);
+		if (error) err(1, "%s", addr.sun_path);
 		attach(sock);
 	} else {
 		error = bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr));
-		if (error) err(EX_CANTCREAT, "%s", addr.sun_path);
+		if (error) err(1, "%s", addr.sun_path);
 		detach(sock, sink, &argv[optind]);
 	}
 }
diff --git a/bin/ever.c b/bin/ever.c
index f983912b..24575617 100644
--- a/bin/ever.c
+++ b/bin/ever.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2017  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -22,12 +22,11 @@
 #include <stdlib.h>
 #include <sys/event.h>
 #include <sys/wait.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 static int watch(int kq, char *path) {
 	int fd = open(path, O_CLOEXEC);
-	if (fd < 0) err(EX_NOINPUT, "%s", path);
+	if (fd < 0) err(1, "%s", path);
 
 	struct kevent event;
 	EV_SET(
@@ -40,7 +39,7 @@ static int watch(int kq, char *path) {
 		path
 	);
 	int nevents = kevent(kq, &event, 1, NULL, 0, NULL);
-	if (nevents < 0) err(EX_OSERR, "kevent");
+	if (nevents < 0) err(1, "kevent");
 
 	return fd;
 }
@@ -48,17 +47,17 @@ static int watch(int kq, char *path) {
 static bool quiet;
 static void exec(int fd, char *const argv[]) {
 	pid_t pid = fork();
-	if (pid < 0) err(EX_OSERR, "fork");
+	if (pid < 0) err(1, "fork");
 
 	if (!pid) {
 		dup2(fd, STDIN_FILENO);
 		execvp(*argv, argv);
-		err(EX_NOINPUT, "%s", *argv);
+		err(127, "%s", *argv);
 	}
 
 	int status;
 	pid = wait(&status);
-	if (pid < 0) err(EX_OSERR, "wait");
+	if (pid < 0) err(1, "wait");
 
 	if (quiet) return;
 	if (WIFEXITED(status)) {
@@ -77,15 +76,15 @@ int main(int argc, char *argv[]) {
 		switch (opt) {
 			break; case 'i': input = true;
 			break; case 'q': quiet = true;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 	argc -= optind;
 	argv += optind;
-	if (argc < 2) return EX_USAGE;
+	if (argc < 2) return 1;
 
 	int kq = kqueue();
-	if (kq < 0) err(EX_OSERR, "kqueue");
+	if (kq < 0) err(1, "kqueue");
 
 	int i;
 	for (i = 0; i < argc - 1; ++i) {
@@ -103,7 +102,7 @@ int main(int argc, char *argv[]) {
 	for (;;) {
 		struct kevent event;
 		int nevents = kevent(kq, NULL, 0, &event, 1, NULL);
-		if (nevents < 0) err(EX_OSERR, "kevent");
+		if (nevents < 0) err(1, "kevent");
 
 		if (event.fflags & NOTE_DELETE) {
 			close(event.ident);
@@ -111,7 +110,7 @@ int main(int argc, char *argv[]) {
 			event.ident = watch(kq, (char *)event.udata);
 		} else if (input) {
 			off_t off = lseek(event.ident, 0, SEEK_SET);
-			if (off < 0) err(EX_IOERR, "lseek");
+			if (off < 0) err(1, "lseek");
 		}
 
 		exec((input ? event.ident : STDIN_FILENO), &argv[i]);
diff --git a/bin/freecell.c b/bin/freecell.c
index 11bed1c0..0110ecfe 100644
--- a/bin/freecell.c
+++ b/bin/freecell.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019, 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019, 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -22,7 +22,6 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -367,7 +366,7 @@ int main(int argc, char *argv[]) {
 		switch (opt) {
 			break; case 'd': delay = strtoul(optarg, NULL, 10);
 			break; case 'n': game = strtoul(optarg, NULL, 10);
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 	curse();
diff --git a/bin/git-comment.pl b/bin/git-comment.pl
index 5100941f..5352702d 100644
--- a/bin/git-comment.pl
+++ b/bin/git-comment.pl
@@ -1,5 +1,5 @@
 #!/usr/bin/env perl
-# Copyright (C) 2021  C. McEnroe <june@causal.agency>
+# Copyright (C) 2021  June McEnroe <june@causal.agency>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published by
diff --git a/bin/glitch.c b/bin/glitch.c
index 9747f35a..4eec2c49 100644
--- a/bin/glitch.c
+++ b/bin/glitch.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2018, 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -14,297 +14,339 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <arpa/inet.h>
 #include <err.h>
+#include <inttypes.h>
+#include <limits.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 #include <zlib.h>
 
-#define PACKED __attribute__((packed))
-
-#define CRC_INIT (crc32(0, Z_NULL, 0))
+#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
 
 static const char *path;
 static FILE *file;
 static uint32_t crc;
 
-static void readExpect(void *ptr, size_t size, const char *expect) {
-	fread(ptr, size, 1, file);
-	if (ferror(file)) err(EX_IOERR, "%s", path);
-	if (feof(file)) errx(EX_DATAERR, "%s: missing %s", path, expect);
-	crc = crc32(crc, ptr, size);
+static void pngRead(void *ptr, size_t len, const char *desc) {
+	size_t n = fread(ptr, len, 1, file);
+	if (!n && ferror(file)) err(1, "%s", path);
+	if (!n) errx(1, "%s: missing %s", path, desc);
+	crc = crc32(crc, ptr, len);
 }
 
-static void writeExpect(const void *ptr, size_t size) {
-	fwrite(ptr, size, 1, file);
-	if (ferror(file)) err(EX_IOERR, "%s", path);
-	crc = crc32(crc, ptr, size);
+static void pngWrite(const void *ptr, size_t len) {
+	size_t n = fwrite(ptr, len, 1, file);
+	if (!n) err(1, "%s", path);
+	crc = crc32(crc, ptr, len);
 }
 
-static const uint8_t Signature[8] = "\x89PNG\r\n\x1A\n";
+static const uint8_t Sig[8] = "\x89PNG\r\n\x1A\n";
 
-static void readSignature(void) {
-	uint8_t signature[8];
-	readExpect(signature, 8, "signature");
-	if (0 != memcmp(signature, Signature, 8)) {
-		errx(EX_DATAERR, "%s: invalid signature", path);
+static void sigRead(void) {
+	uint8_t sig[sizeof(Sig)];
+	pngRead(sig, sizeof(sig), "signature");
+	if (memcmp(sig, Sig, sizeof(sig))) {
+		errx(1, "%s: invalid signature", path);
 	}
 }
 
-static void writeSignature(void) {
-	writeExpect(Signature, sizeof(Signature));
+static void sigWrite(void) {
+	pngWrite(Sig, sizeof(Sig));
 }
 
-struct PACKED Chunk {
-	uint32_t size;
-	char type[4];
-};
+static uint32_t u32Read(const char *desc) {
+	uint8_t b[4];
+	pngRead(b, sizeof(b), desc);
+	return (uint32_t)b[0] << 24 | (uint32_t)b[1] << 16
+		| (uint32_t)b[2] << 8 | (uint32_t)b[3];
+}
 
-static const char *typeStr(struct Chunk chunk) {
-	static char buf[5];
-	memcpy(buf, chunk.type, 4);
-	return buf;
+static void u32Write(uint32_t x) {
+	uint8_t b[4] = { x >> 24 & 0xFF, x >> 16 & 0xFF, x >> 8 & 0xFF, x & 0xFF };
+	pngWrite(b, sizeof(b));
 }
 
-static struct Chunk readChunk(void) {
+struct Chunk {
+	uint32_t len;
+	char type[5];
+};
+
+static struct Chunk chunkRead(void) {
 	struct Chunk chunk;
-	readExpect(&chunk, sizeof(chunk), "chunk");
-	chunk.size = ntohl(chunk.size);
-	crc = crc32(CRC_INIT, (Byte *)chunk.type, sizeof(chunk.type));
+	chunk.len = u32Read("chunk length");
+	crc = crc32(0, Z_NULL, 0);
+	pngRead(chunk.type, 4, "chunk type");
+	chunk.type[4] = 0;
 	return chunk;
 }
 
-static void writeChunk(struct Chunk chunk) {
-	chunk.size = htonl(chunk.size);
-	writeExpect(&chunk, sizeof(chunk));
-	crc = crc32(CRC_INIT, (Byte *)chunk.type, sizeof(chunk.type));
+static void chunkWrite(struct Chunk chunk) {
+	u32Write(chunk.len);
+	crc = crc32(0, Z_NULL, 0);
+	pngWrite(chunk.type, 4);
 }
 
-static void readCrc(void) {
-	uint32_t expected = crc;
-	uint32_t found;
-	readExpect(&found, sizeof(found), "CRC32");
-	found = ntohl(found);
-	if (found != expected) {
-		errx(
-			EX_DATAERR, "%s: expected CRC32 %08X, found %08X",
-			path, expected, found
-		);
-	}
+static void crcRead(void) {
+	uint32_t expect = crc;
+	uint32_t actual = u32Read("CRC32");
+	if (actual == expect) return;
+	errx(
+		1, "%s: expected CRC32 %08X, found %08X",
+		path, expect, actual
+	);
 }
 
-static void writeCrc(void) {
-	uint32_t net = htonl(crc);
-	writeExpect(&net, sizeof(net));
+static void crcWrite(void) {
+	u32Write(crc);
 }
 
-static void skipChunk(struct Chunk chunk) {
-	uint8_t discard[chunk.size];
-	readExpect(discard, sizeof(discard), "chunk data");
-	readCrc();
+static void chunkSkip(struct Chunk chunk) {
+	if (!(chunk.type[0] & 0x20)) {
+		errx(1, "%s: unsupported critical chunk %s", path, chunk.type);
+	}
+	uint8_t buf[4096];
+	while (chunk.len > sizeof(buf)) {
+		pngRead(buf, sizeof(buf), "chunk data");
+		chunk.len -= sizeof(buf);
+	}
+	if (chunk.len) pngRead(buf, chunk.len, "chunk data");
+	crcRead();
 }
 
-static struct PACKED {
+enum Color {
+	Grayscale = 0,
+	Truecolor = 2,
+	Indexed = 3,
+	GrayscaleAlpha = 4,
+	TruecolorAlpha = 6,
+};
+enum Compression {
+	Deflate,
+};
+enum FilterMethod {
+	Adaptive,
+};
+enum Interlace {
+	Progressive,
+	Adam7,
+};
+
+enum { HeaderLen = 13 };
+static struct {
 	uint32_t width;
 	uint32_t height;
 	uint8_t depth;
-	enum PACKED {
-		Grayscale      = 0,
-		Truecolor      = 2,
-		Indexed        = 3,
-		GrayscaleAlpha = 4,
-		TruecolorAlpha = 6,
-	} color;
+	uint8_t color;
 	uint8_t compression;
 	uint8_t filter;
 	uint8_t interlace;
 } header;
-_Static_assert(13 == sizeof(header), "header size");
 
-static size_t pixelBits(void) {
+static size_t pixelLen;
+static size_t lineLen;
+static size_t dataLen;
+
+static void recalc(void) {
+	size_t pixelBits = header.depth;
 	switch (header.color) {
-		case Grayscale:      return 1 * header.depth;
-		case Truecolor:      return 3 * header.depth;
-		case Indexed:        return 1 * header.depth;
-		case GrayscaleAlpha: return 2 * header.depth;
-		case TruecolorAlpha: return 4 * header.depth;
-		default: abort();
+		break; case GrayscaleAlpha: pixelBits *= 2;
+		break; case Truecolor: pixelBits *= 3;
+		break; case TruecolorAlpha: pixelBits *= 4;
 	}
+	pixelLen = (pixelBits + 7) / 8;
+	lineLen = (header.width * pixelBits + 7) / 8;
+	dataLen = (1 + lineLen) * header.height;
 }
 
-static size_t pixelSize(void) {
-	return (pixelBits() + 7) / 8;
+static void headerRead(struct Chunk chunk) {
+	if (chunk.len != HeaderLen) {
+		errx(
+			1, "%s: expected %s length %" PRIu32 ", found %" PRIu32,
+			path, chunk.type, (uint32_t)HeaderLen, chunk.len
+		);
+	}
+	header.width = u32Read("header width");
+	header.height = u32Read("header height");
+	pngRead(&header.depth, 1, "header depth");
+	pngRead(&header.color, 1, "header color");
+	pngRead(&header.compression, 1, "header compression");
+	pngRead(&header.filter, 1, "header filter");
+	pngRead(&header.interlace, 1, "header interlace");
+	crcRead();
+	recalc();
+}
+
+static void headerWrite(void) {
+	struct Chunk ihdr = { HeaderLen, "IHDR" };
+	chunkWrite(ihdr);
+	u32Write(header.width);
+	u32Write(header.height);
+	pngWrite(&header.depth, 1);
+	pngWrite(&header.color, 1);
+	pngWrite(&header.compression, 1);
+	pngWrite(&header.filter, 1);
+	pngWrite(&header.interlace, 1);
+	crcWrite();
 }
 
-static size_t lineSize(void) {
-	return (header.width * pixelBits() + 7) / 8;
-}
+static struct {
+	uint32_t len;
+	uint8_t rgb[256][3];
+} pal;
 
-static size_t dataSize(void) {
-	return (1 + lineSize()) * header.height;
+static struct {
+	uint32_t len;
+	uint8_t a[256];
+} trans;
+
+static void palClear(void) {
+	pal.len = 0;
+	trans.len = 0;
 }
 
-static void readHeader(void) {
-	struct Chunk ihdr = readChunk();
-	if (0 != memcmp(ihdr.type, "IHDR", 4)) {
-		errx(EX_DATAERR, "%s: expected IHDR, found %s", path, typeStr(ihdr));
+static void palRead(struct Chunk chunk) {
+	if (chunk.len % 3) {
+		errx(
+			1, "%s: %s length %" PRIu32 " not divisible by 3",
+			path, chunk.type, chunk.len
+		);
 	}
-	if (ihdr.size != sizeof(header)) {
+	pal.len = chunk.len / 3;
+	if (pal.len > 256) {
 		errx(
-			EX_DATAERR, "%s: expected IHDR size %zu, found %u",
-			path, sizeof(header), ihdr.size
+			1, "%s: %s length %" PRIu32 " > 256",
+			path, chunk.type, pal.len
 		);
 	}
-	readExpect(&header, sizeof(header), "header");
-	readCrc();
-	header.width = ntohl(header.width);
-	header.height = ntohl(header.height);
-	if (!header.width) errx(EX_DATAERR, "%s: invalid width 0", path);
-	if (!header.height) errx(EX_DATAERR, "%s: invalid height 0", path);
+	pngRead(pal.rgb, chunk.len, "palette data");
+	crcRead();
 }
 
-static void writeHeader(void) {
-	struct Chunk ihdr = { .size = sizeof(header), .type = "IHDR" };
-	writeChunk(ihdr);
-	header.width = htonl(header.width);
-	header.height = htonl(header.height);
-	writeExpect(&header, sizeof(header));
-	writeCrc();
-	header.width = ntohl(header.width);
-	header.height = ntohl(header.height);
+static void palWrite(void) {
+	struct Chunk plte = { 3 * pal.len, "PLTE" };
+	chunkWrite(plte);
+	pngWrite(pal.rgb, plte.len);
+	crcWrite();
 }
 
-static struct {
-	uint32_t len;
-	uint8_t entries[256][3];
-} palette;
-
-static void readPalette(void) {
-	struct Chunk chunk;
-	for (;;) {
-		chunk = readChunk();
-		if (0 == memcmp(chunk.type, "PLTE", 4)) break;
-		skipChunk(chunk);
+static void transRead(struct Chunk chunk) {
+	trans.len = chunk.len;
+	if (trans.len > 256) {
+		errx(
+			1, "%s: %s length %" PRIu32 " > 256",
+			path, chunk.type, trans.len
+		);
 	}
-	palette.len = chunk.size / 3;
-	readExpect(palette.entries, chunk.size, "palette data");
-	readCrc();
+	pngRead(trans.a, chunk.len, "transparency data");
+	crcRead();
 }
 
-static void writePalette(void) {
-	struct Chunk plte = { .size = 3 * palette.len, .type = "PLTE" };
-	writeChunk(plte);
-	writeExpect(palette.entries, plte.size);
-	writeCrc();
+static void transWrite(void) {
+	struct Chunk trns = { trans.len, "tRNS" };
+	chunkWrite(trns);
+	pngWrite(trans.a, trns.len);
+	crcWrite();
 }
 
 static uint8_t *data;
 
-static void readData(void) {
-	data = malloc(dataSize());
-	if (!data) err(EX_OSERR, "malloc(%zu)", dataSize());
+static void dataAlloc(void) {
+	data = malloc(dataLen);
+	if (!data) err(1, "malloc");
+}
 
-	struct z_stream_s stream = { .next_out = data, .avail_out = dataSize() };
+static void dataRead(struct Chunk chunk) {
+	z_stream stream = { .next_out = data, .avail_out = dataLen };
 	int error = inflateInit(&stream);
-	if (error != Z_OK) errx(EX_SOFTWARE, "%s: inflateInit: %s", path, stream.msg);
+	if (error != Z_OK) errx(1, "inflateInit: %s", stream.msg);
 
 	for (;;) {
-		struct Chunk chunk = readChunk();
-		if (0 == memcmp(chunk.type, "IDAT", 4)) {
-			uint8_t *idat = malloc(chunk.size);
-			if (!idat) err(EX_OSERR, "malloc");
-
-			readExpect(idat, chunk.size, "image data");
-			readCrc();
+		if (strcmp(chunk.type, "IDAT")) {
+			errx(1, "%s: missing IDAT chunk", path);
+		}
 
-			stream.next_in = idat;
-			stream.avail_in = chunk.size;
-			int error = inflate(&stream, Z_SYNC_FLUSH);
-			free(idat);
+		uint8_t *idat = malloc(chunk.len);
+		if (!idat) err(1, "malloc");
 
-			if (error == Z_STREAM_END) break;
-			if (error != Z_OK) errx(EX_DATAERR, "%s: inflate: %s", path, stream.msg);
+		pngRead(idat, chunk.len, "image data");
+		crcRead();
+		
+		stream.next_in = idat;
+		stream.avail_in = chunk.len;
+		error = inflate(&stream, Z_SYNC_FLUSH);
+		free(idat);
 
-		} else if (0 == memcmp(chunk.type, "IEND", 4)) {
-			errx(EX_DATAERR, "%s: missing IDAT chunk", path);
-		} else {
-			skipChunk(chunk);
+		if (error == Z_STREAM_END) break;
+		if (error != Z_OK) {
+			errx(1, "%s: inflate: %s", path, stream.msg);
 		}
-	}
 
+		chunk = chunkRead();
+	}
 	inflateEnd(&stream);
-	if ((size_t)stream.total_out != dataSize()) {
+	if ((size_t)stream.total_out != dataLen) {
 		errx(
-			EX_DATAERR, "%s: expected data size %zu, found %zu",
-			path, dataSize(), (size_t)stream.total_out
+			1, "%s: expected data length %zu, found %zu",
+			path, dataLen, (size_t)stream.total_out
 		);
 	}
 }
 
-static void writeData(void) {
-	uLong size = compressBound(dataSize());
-	uint8_t *deflate = malloc(size);
-	if (!deflate) err(EX_OSERR, "malloc");
+static void dataWrite(void) {
+	z_stream stream = {
+		.next_in = data,
+		.avail_in = dataLen,
+	};
+	int error = deflateInit2(
+		&stream, Z_BEST_COMPRESSION, Z_DEFLATED, 15, 8, Z_FILTERED
+	);
+	if (error != Z_OK) errx(1, "deflateInit2: %s", stream.msg);
 
-	int error = compress2(deflate, &size, data, dataSize(), Z_BEST_SPEED);
-	if (error != Z_OK) errx(EX_SOFTWARE, "%s: compress2: %d", path, error);
+	uLong bound = deflateBound(&stream, dataLen);
+	uint8_t *buf = malloc(bound);
+	if (!buf) err(1, "malloc");
 
-	struct Chunk idat = { .size = size, .type = "IDAT" };
-	writeChunk(idat);
-	writeExpect(deflate, size);
-	writeCrc();
+	stream.next_out = buf;
+	stream.avail_out = bound;
+	deflate(&stream, Z_FINISH);
+	deflateEnd(&stream);
 
-	free(deflate);
-}
+	struct Chunk idat = { stream.total_out, "IDAT" };
+	chunkWrite(idat);
+	pngWrite(buf, stream.total_out);
+	crcWrite();
+	free(buf);
 
-static void writeEnd(void) {
-	struct Chunk iend = { .size = 0, .type = "IEND" };
-	writeChunk(iend);
-	writeCrc();
+	struct Chunk iend = { 0, "IEND" };
+	chunkWrite(iend);
+	crcWrite();
 }
 
-enum PACKED Filter {
+enum Filter {
 	None,
 	Sub,
 	Up,
 	Average,
 	Paeth,
-	FilterCount,
+	FilterCap,
 };
 
-static struct {
-	bool brokenPaeth;
-	bool filt;
-	bool recon;
-	uint8_t declareFilter;
-	uint8_t applyFilter;
-	enum Filter declareFilters[255];
-	enum Filter applyFilters[255];
-	bool invert;
-	bool mirror;
-	bool zeroX;
-	bool zeroY;
-} options;
-
 struct Bytes {
-	uint8_t x;
-	uint8_t a;
-	uint8_t b;
-	uint8_t c;
+	uint8_t x, a, b, c;
 };
 
+static bool brokenPaeth;
 static uint8_t paethPredictor(struct Bytes f) {
 	int32_t p = (int32_t)f.a + (int32_t)f.b - (int32_t)f.c;
-	int32_t pa = abs(p - (int32_t)f.a);
-	int32_t pb = abs(p - (int32_t)f.b);
-	int32_t pc = abs(p - (int32_t)f.c);
+	int32_t pa = labs(p - (int32_t)f.a);
+	int32_t pb = labs(p - (int32_t)f.b);
+	int32_t pc = labs(p - (int32_t)f.c);
 	if (pa <= pb && pa <= pc) return f.a;
-	if (options.brokenPaeth) {
+	if (brokenPaeth) {
 		if (pb < pc) return f.b;
 	} else {
 		if (pb <= pc) return f.b;
@@ -319,7 +361,7 @@ static uint8_t recon(enum Filter type, struct Bytes f) {
 		case Up:      return f.x + f.b;
 		case Average: return f.x + ((uint32_t)f.a + (uint32_t)f.b) / 2;
 		case Paeth:   return f.x + paethPredictor(f);
-		default:      abort();
+		default: abort();
 	}
 }
 
@@ -330,59 +372,59 @@ static uint8_t filt(enum Filter type, struct Bytes f) {
 		case Up:      return f.x - f.b;
 		case Average: return f.x - ((uint32_t)f.a + (uint32_t)f.b) / 2;
 		case Paeth:   return f.x - paethPredictor(f);
-		default:      abort();
+		default: abort();
 	}
 }
 
-static struct Line {
-	enum Filter type;
-	uint8_t data[];
-} **lines;
-
-static void scanlines(void) {
-	lines = calloc(header.height, sizeof(*lines));
-	if (!lines) err(EX_OSERR, "calloc(%u, %zu)", header.height, sizeof(*lines));
-
-	size_t stride = 1 + lineSize();
-	for (uint32_t y = 0; y < header.height; ++y) {
-		lines[y] = (struct Line *)&data[y * stride];
-		if (lines[y]->type >= FilterCount) {
-			errx(EX_DATAERR, "%s: invalid filter type %hhu", path, lines[y]->type);
-		}
-	}
+static uint8_t *lineType(uint32_t y) {
+	return &data[y * (1 + lineLen)];
+}
+static uint8_t *lineData(uint32_t y) {
+	return 1 + lineType(y);
 }
 
 static struct Bytes origBytes(uint32_t y, size_t i) {
-	bool a = (i >= pixelSize()), b = (y > 0), c = (a && b);
+	bool a = (i >= pixelLen), b = (y > 0), c = (a && b);
 	return (struct Bytes) {
-		.x = lines[y]->data[i],
-		.a = a ? lines[y]->data[i - pixelSize()] : 0,
-		.b = b ? lines[y - 1]->data[i] : 0,
-		.c = c ? lines[y - 1]->data[i - pixelSize()] : 0,
+		.x = lineData(y)[i],
+		.a = (a ? lineData(y)[i-pixelLen] : 0),
+		.b = (b ? lineData(y-1)[i] : 0),
+		.c = (c ? lineData(y-1)[i-pixelLen] : 0),
 	};
 }
 
-static void reconData(void) {
+static bool reconFilter;
+static void dataRecon(void) {
 	for (uint32_t y = 0; y < header.height; ++y) {
-		for (size_t i = 0; i < lineSize(); ++i) {
-			if (options.filt) {
-				lines[y]->data[i] = filt(lines[y]->type, origBytes(y, i));
+		for (size_t i = 0; i < lineLen; ++i) {
+			if (reconFilter) {
+				lineData(y)[i] = filt(*lineType(y), origBytes(y, i));
 			} else {
-				lines[y]->data[i] = recon(lines[y]->type, origBytes(y, i));
+				lineData(y)[i] = recon(*lineType(y), origBytes(y, i));
 			}
 		}
-		lines[y]->type = None;
+		*lineType(y) = None;
 	}
 }
 
-static void filterData(void) {
-	for (uint32_t y = header.height - 1; y < header.height; --y) {
-		uint8_t filter[FilterCount][lineSize()];
-		uint32_t heuristic[FilterCount] = {0};
+static bool filterRecon;
+static size_t applyFilter;
+static enum Filter applyFilters[256];
+static size_t declFilter;
+static enum Filter declFilters[256];
+
+static void dataFilter(void) {
+	uint8_t *filter[FilterCap];
+	for (enum Filter i = None; i < FilterCap; ++i) {
+		filter[i] = malloc(lineLen);
+		if (!filter[i]) err(1, "malloc");
+	}
+	for (uint32_t y = header.height-1; y < header.height; --y) {
+		uint32_t heuristic[FilterCap] = {0};
 		enum Filter minType = None;
-		for (enum Filter type = None; type < FilterCount; ++type) {
-			for (size_t i = 0; i < lineSize(); ++i) {
-				if (options.recon) {
+		for (enum Filter type = None; type < FilterCap; ++type) {
+			for (size_t i = 0; i < lineLen; ++i) {
+				if (filterRecon) {
 					filter[type][i] = recon(type, origBytes(y, i));
 				} else {
 					filter[type][i] = filt(type, origBytes(y, i));
@@ -391,148 +433,172 @@ static void filterData(void) {
 			}
 			if (heuristic[type] < heuristic[minType]) minType = type;
 		}
-
-		if (options.declareFilter) {
-			lines[y]->type = options.declareFilters[y % options.declareFilter];
+		if (declFilter) {
+			*lineType(y) = declFilters[y % declFilter];
 		} else {
-			lines[y]->type = minType;
+			*lineType(y) = minType;
 		}
-
-		if (options.applyFilter) {
-			enum Filter type = options.applyFilters[y % options.applyFilter];
-			memcpy(lines[y]->data, filter[type], lineSize());
+		if (applyFilter) {
+			memcpy(lineData(y), filter[applyFilters[y % applyFilter]], lineLen);
 		} else {
-			memcpy(lines[y]->data, filter[minType], lineSize());
+			memcpy(lineData(y), filter[minType], lineLen);
 		}
 	}
-}
-
-static void invert(void) {
-	for (uint32_t y = 0; y < header.height; ++y) {
-		for (size_t i = 0; i < lineSize(); ++i) {
-			lines[y]->data[i] ^= 0xFF;
-		}
-	}
-}
-
-static void mirror(void) {
-	for (uint32_t y = 0; y < header.height; ++y) {
-		for (size_t i = 0, j = lineSize() - 1; i < j; ++i, --j) {
-			uint8_t t = lines[y]->data[i];
-			lines[y]->data[i] = lines[y]->data[j];
-			lines[y]->data[j] = t;
-		}
+	for (enum Filter i = None; i < FilterCap; ++i) {
+		free(filter[i]);
 	}
 }
 
-static void zeroX(void) {
-	for (uint32_t y = 0; y < header.height; ++y) {
-		memset(lines[y]->data, 0, pixelSize());
-	}
-}
-
-static void zeroY(void) {
-	memset(lines[0]->data, 0, lineSize());
-}
+static bool invertData;
+static bool mirrorData;
+static bool zeroX;
+static bool zeroY;
 
 static void glitch(const char *inPath, const char *outPath) {
 	if (inPath) {
 		path = inPath;
 		file = fopen(path, "r");
-		if (!file) err(EX_NOINPUT, "%s", path);
+		if (!file) err(1, "%s", path);
 	} else {
-		path = "(stdin)";
+		path = "stdin";
 		file = stdin;
 	}
 
-	readSignature();
-	readHeader();
-	if (header.color == Indexed) readPalette();
-	readData();
+	sigRead();
+	struct Chunk ihdr = chunkRead();
+	if (strcmp(ihdr.type, "IHDR")) {
+		errx(1, "%s: expected IHDR, found %s", path, ihdr.type);
+	}
+	headerRead(ihdr);
+	if (header.interlace != Progressive) {
+		errx(1, "%s: unsupported interlacing", path);
+	}
+
+	palClear();
+	dataAlloc();
+	for (;;) {
+		struct Chunk chunk = chunkRead();
+		if (!strcmp(chunk.type, "PLTE")) {
+			palRead(chunk);
+		} else if (!strcmp(chunk.type, "tRNS")) {
+			transRead(chunk);
+		} else if (!strcmp(chunk.type, "IDAT")) {
+			dataRead(chunk);
+		} else if (!strcmp(chunk.type, "IEND")) {
+			break;
+		} else {
+			chunkSkip(chunk);
+		}
+	}
 	fclose(file);
 
-	scanlines();
-	reconData();
-	filterData();
-	if (options.invert) invert();
-	if (options.mirror) mirror();
-	if (options.zeroX) zeroX();
-	if (options.zeroY) zeroY();
-	free(lines);
+	dataRecon();
+	dataFilter();
+
+	if (invertData) {
+		for (uint32_t y = 0; y < header.height; ++y) {
+			for (size_t i = 0; i < lineLen; ++i) {
+				lineData(y)[i] ^= 0xFF;
+			}
+		}
+	}
+	if (mirrorData) {
+		for (uint32_t y = 0; y < header.height; ++y) {
+			for (size_t i = 0, j = lineLen-1; i < j; ++i, --j) {
+				uint8_t x = lineData(y)[i];
+				lineData(y)[i] = lineData(y)[j];
+				lineData(y)[j] = x;
+			}
+		}
+	}
+	if (zeroX) {
+		for (uint32_t y = 0; y < header.height; ++y) {
+			memset(lineData(y), 0, pixelLen);
+		}
+	}
+	if (zeroY) {
+		memset(lineData(0), 0, lineLen);
+	}
 
+	char buf[PATH_MAX];
 	if (outPath) {
 		path = outPath;
-		file = fopen(path, "w");
-		if (!file) err(EX_CANTCREAT, "%s", path);
+		if (outPath == inPath) {
+			snprintf(buf, sizeof(buf), "%sg", outPath);
+			file = fopen(buf, "wx");
+			if (!file) err(1, "%s", buf);
+		} else {
+			file = fopen(path, "w");
+			if (!file) err(1, "%s", outPath);
+		}
 	} else {
-		path = "(stdout)";
+		path = "stdout";
 		file = stdout;
 	}
 
-	writeSignature();
-	writeHeader();
-	if (header.color == Indexed) writePalette();
-	writeData();
-	writeEnd();
+	sigWrite();
+	headerWrite();
+	if (header.color == Indexed) {
+		palWrite();
+		if (trans.len) transWrite();
+	}
+	dataWrite();
 	free(data);
-
 	int error = fclose(file);
-	if (error) err(EX_IOERR, "%s", path);
+	if (error) err(1, "%s", path);
+
+	if (outPath && outPath == inPath) {
+		error = rename(buf, outPath);
+		if (error) err(1, "%s", outPath);
+	}
 }
 
-static enum Filter parseFilter(const char *s) {
-	switch (s[0]) {
+static enum Filter parseFilter(const char *str) {
+	switch (str[0]) {
 		case 'N': case 'n': return None;
 		case 'S': case 's': return Sub;
 		case 'U': case 'u': return Up;
 		case 'A': case 'a': return Average;
 		case 'P': case 'p': return Paeth;
-		default: errx(EX_USAGE, "invalid filter type %s", s);
+		default: errx(1, "invalid filter type %s", str);
 	}
 }
 
-static uint8_t parseFilters(enum Filter *filters, const char *s) {
-	uint8_t len = 0;
-	do {
-		filters[len++] = parseFilter(s);
-		s = strchr(s, ',');
-	} while (s++);
+static size_t parseFilters(enum Filter *filters, char *str) {
+	size_t len = 0;
+	while (str) {
+		char *filt = strsep(&str, ",");
+		filters[len++] = parseFilter(filt);
+	}
 	return len;
 }
 
 int main(int argc, char *argv[]) {
 	bool stdio = false;
-	char *output = NULL;
+	char *outPath = NULL;
 
-	int opt;
-	while (0 < (opt = getopt(argc, argv, "a:cd:fimo:prxy"))) {
+	for (int opt; 0 < (opt = getopt(argc, argv, "a:cd:fimo:prxy"));) {
 		switch (opt) {
-			break; case 'a':
-				options.applyFilter = parseFilters(options.applyFilters, optarg);
+			break; case 'a': applyFilter = parseFilters(applyFilters, optarg);
 			break; case 'c': stdio = true;
-			break; case 'd':
-				options.declareFilter = parseFilters(options.declareFilters, optarg);
-			break; case 'f': options.filt = true;
-			break; case 'i': options.invert = true;
-			break; case 'm': options.mirror = true;
-			break; case 'o': output = optarg;
-			break; case 'p': options.brokenPaeth = true;
-			break; case 'r': options.recon = true;
-			break; case 'x': options.zeroX = true;
-			break; case 'y': options.zeroY = true;
-			break; default: return EX_USAGE;
+			break; case 'd': declFilter = parseFilters(declFilters, optarg);
+			break; case 'f': reconFilter = true;
+			break; case 'i': invertData = true;
+			break; case 'm': mirrorData = true;
+			break; case 'o': outPath = optarg;
+			break; case 'p': brokenPaeth = true;
+			break; case 'r': filterRecon = true;
+			break; case 'x': zeroX = true;
+			break; case 'y': zeroY = true;
+			break; default:  return 1;
 		}
 	}
 
-	if (argc - optind == 1 && (output || stdio)) {
-		glitch(argv[optind], output);
-	} else if (optind < argc) {
+	if (optind < argc) {
 		for (int i = optind; i < argc; ++i) {
-			glitch(argv[i], argv[i]);
+			glitch(argv[i], (stdio ? NULL : outPath ? outPath : argv[i]));
 		}
 	} else {
-		glitch(NULL, output);
+		glitch(NULL, outPath);
 	}
-
-	return EX_OK;
 }
diff --git a/bin/hilex.c b/bin/hilex.c
index 0bcc5c7f..81485ab2 100644
--- a/bin/hilex.c
+++ b/bin/hilex.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/wait.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 #include "hilex.h"
@@ -53,7 +52,7 @@ static const struct {
 	{ &LexC, "c", "[.][chlmy]$", NULL },
 	{ &LexMake, "make", "[.](mk|am)$|^Makefile$", NULL },
 	{ &LexMdoc, "mdoc", "[.][1-9]$", "^[.]Dd" },
-	{ &LexSh, "sh", "[.]sh$|^[.](profile|shrc)$", "^#![ ]?/bin/sh" },
+	{ &LexSh, "sh", "[.]sh$|^[.](profile|shrc)$", "^#![ ]?/bin/k?sh" },
 	{ &LexText, "text", "[.]txt$", NULL },
 };
 
@@ -61,14 +60,14 @@ static const struct Lexer *parseLexer(const char *name) {
 	for (size_t i = 0; i < ARRAY_LEN(Lexers); ++i) {
 		if (!strcmp(name, Lexers[i].name)) return Lexers[i].lexer;
 	}
-	errx(EX_USAGE, "unknown lexer %s", name);
+	errx(1, "unknown lexer %s", name);
 }
 
 static void ungets(const char *str, FILE *file) {
 	size_t len = strlen(str);
 	for (size_t i = len-1; i < len; --i) {
 		int ch = ungetc(str[i], file);
-		if (ch == EOF) errx(EX_IOERR, "cannot push back string");
+		if (ch == EOF) errx(1, "cannot push back string");
 	}
 }
 
@@ -134,16 +133,16 @@ static void ansiHeader(const char *opts[]) {
 
 	int rw[2];
 	int error = pipe(rw);
-	if (error) err(EX_OSERR, "pipe");
+	if (error) err(1, "pipe");
 
 	pid_t pid = fork();
-	if (pid < 0) err(EX_OSERR, "fork");
+	if (pid < 0) err(1, "fork");
 	if (!pid) {
 		dup2(rw[0], STDIN_FILENO);
 		close(rw[0]);
 		close(rw[1]);
 		execl(shell, shell, "-c", pager, NULL);
-		err(EX_CONFIG, "%s", shell);
+		err(127, "%s", shell);
 	}
 	dup2(rw[1], STDOUT_FILENO);
 	close(rw[0]);
@@ -152,7 +151,7 @@ static void ansiHeader(const char *opts[]) {
 
 #ifdef __OpenBSD__
 	error = pledge("stdio", NULL);
-	if (error) err(EX_OSERR, "pledge");
+	if (error) err(1, "pledge");
 #endif
 }
 
@@ -330,7 +329,7 @@ static const struct Formatter *parseFormatter(const char *name) {
 	for (size_t i = 0; i < ARRAY_LEN(Formatters); ++i) {
 		if (!strcmp(name, Formatters[i].name)) return &Formatters[i];
 	}
-	errx(EX_USAGE, "unknown formatter %s", name);
+	errx(1, "unknown formatter %s", name);
 }
 
 static char *const OptionKeys[OptionCap + 1] = {
@@ -356,12 +355,12 @@ int main(int argc, char *argv[]) {
 				while (*optarg) {
 					char *val;
 					int key = getsubopt(&optarg, OptionKeys, &val);
-					if (key < 0) errx(EX_USAGE, "no such option %s", val);
+					if (key < 0) errx(1, "no such option %s", val);
 					opts[key] = (val ? val : "");
 				}
 			}
 			break; case 't': text = true;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 
@@ -370,7 +369,7 @@ int main(int argc, char *argv[]) {
 	if (optind < argc) {
 		path = argv[optind];
 		file = fopen(path, "r");
-		if (!file) err(EX_NOINPUT, "%s", path);
+		if (!file) err(1, "%s", path);
 		pager = isatty(STDOUT_FILENO);
 	}
 
@@ -381,7 +380,7 @@ int main(int argc, char *argv[]) {
 	} else {
 		error = pledge("stdio", NULL);
 	}
-	if (error) err(EX_OSERR, "pledge");
+	if (error) err(1, "pledge");
 #endif
 
 	if (!name) {
@@ -394,7 +393,7 @@ int main(int argc, char *argv[]) {
 	if (!opts[Title]) opts[Title] = name;
 	if (!lexer) lexer = matchLexer(name, file);
 	if (!lexer && text) lexer = &LexText;
-	if (!lexer) errx(EX_USAGE, "cannot infer lexer for %s", name);
+	if (!lexer) errx(1, "cannot infer lexer for %s", name);
 
 	*lexer->in = file;
 	if (formatter->header) formatter->header(opts);
diff --git a/bin/hilex.h b/bin/hilex.h
index 882b5f95..b57fc8cc 100644
--- a/bin/hilex.h
+++ b/bin/hilex.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
diff --git a/bin/htagml.c b/bin/htagml.c
index 1f547be6..c35cdb15 100644
--- a/bin/htagml.c
+++ b/bin/htagml.c
@@ -20,12 +20,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 static char *deregex(const char *patt) {
 	char *buf = malloc(strlen(patt) + 1);
-	if (!buf) err(EX_OSERR, "malloc");
+	if (!buf) err(1, "malloc");
 	char *ptr = buf;
 	if (*patt == '^') patt++;
 	for (; *patt; ++patt) {
@@ -94,21 +93,21 @@ int main(int argc, char *argv[]) {
 			break; case 'm': main = true;
 			break; case 'p': pre = true;
 			break; case 'x': index = true;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
-	if (optind == argc) errx(EX_USAGE, "name required");
+	if (optind == argc) errx(1, "name required");
 	const char *name = argv[optind];
 
 	FILE *file = fopen(name, "r");
-	if (!file) err(EX_NOINPUT, "%s", name);
+	if (!file) err(1, "%s", name);
 
 	FILE *tagsFile = fopen(tagsPath, "r");
-	if (!tagsFile) err(EX_NOINPUT, "%s", tagsPath);
+	if (!tagsFile) err(1, "%s", tagsPath);
 
 #ifdef __OpenBSD__
 	int error = pledge("stdio", NULL);
-	if (error) err(EX_OSERR, "pledge");
+	if (error) err(1, "pledge");
 #endif
 
 	size_t len = 0;
@@ -119,7 +118,7 @@ int main(int argc, char *argv[]) {
 		char *str;
 		size_t len;
 	} *tags = malloc(cap * sizeof(*tags));
-	if (!tags) err(EX_OSERR, "malloc");
+	if (!tags) err(1, "malloc");
 
 	char *buf = NULL;
 	size_t bufCap = 0;
@@ -128,15 +127,15 @@ int main(int argc, char *argv[]) {
 		char *tag = strsep(&line, "\t");
 		char *file = strsep(&line, "\t");
 		char *def = strsep(&line, "\n");
-		if (!tag || !file || !def) errx(EX_DATAERR, "malformed tags file");
+		if (!tag || !file || !def) errx(1, "malformed tags file");
 
 		if (strcmp(file, name)) continue;
 		if (len == cap) {
 			tags = realloc(tags, (cap *= 2) * sizeof(*tags));
-			if (!tags) err(EX_OSERR, "realloc");
+			if (!tags) err(1, "realloc");
 		}
 		tags[len].tag = strdup(tag);
-		if (!tags[len].tag) err(EX_OSERR, "strdup");
+		if (!tags[len].tag) err(1, "strdup");
 
 		tags[len].num = 0;
 		if (def[0] == '/' || def[0] == '?') {
@@ -184,7 +183,7 @@ int main(int argc, char *argv[]) {
 		if (pipe) {
 			ssize_t len = getline(&buf, &bufCap, stdin);
 			if (len < 0) {
-				errx(EX_DATAERR, "missing line %d on standard input", num);
+				errx(1, "missing line %d on standard input", num);
 			}
 		}
 		if (!tag) {
diff --git a/bin/make.l b/bin/make.l
index ae1be2f5..6296716d 100644
--- a/bin/make.l
+++ b/bin/make.l
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
diff --git a/bin/man1/qf.1 b/bin/man1/qf.1
new file mode 100644
index 00000000..8828d723
--- /dev/null
+++ b/bin/man1/qf.1
@@ -0,0 +1,71 @@
+.Dd June  2, 2022
+.Dt QF 1
+.Os
+.
+.Sh NAME
+.Nm qf
+.Nd grep pager
+.
+.Sh SYNOPSIS
+.Nm Op Ar pattern
+.
+.Sh DESCRIPTION
+.Nm
+is a pager for
+.Xr grep 1 ,
+.Xr ag 1 ,
+.Xr rg 1 ,
+etc.\&
+which allows
+jumping to matches in
+.Ev $EDITOR .
+It parses any input
+prefixed by path
+and line number
+separated by a colon
+.Ql ":"
+followed by either a colon
+or a hyphen
+.Ql "-" .
+It otherwise operates similar to
+.Xr less 1 .
+.
+.Pp
+If
+.Ar pattern
+is given,
+the first match on each line
+will be highlighted.
+The
+.Ar pattern
+is interpreted as
+an extended regular expression
+and is matched case-insensitively
+unless it contains an uppercase letter.
+.
+.Pp
+The keys are as follows:
+.Bl -tag -width Ds
+.It Ic Enter
+Open the currently selected line in
+.Ev $EDITOR .
+When the editor exits,
+.Nm
+resumes.
+.It Ic {}
+Jump between files.
+.It Ic gG
+Jump to first or last line.
+.It Ic jk
+Move to next or previous line.
+.It Ic nN
+Jump to next or previous match line.
+.It Ic q
+Exit.
+.It Ic r
+Refresh the display.
+.El
+.
+.Sh EXAMPLES
+.Dl $ ag -C open | qf
+.Dl $ git grep -n open | qf
diff --git a/bin/man1/up.1 b/bin/man1/up.1
index 2240b99a..aece79bd 100644
--- a/bin/man1/up.1
+++ b/bin/man1/up.1
@@ -1,4 +1,4 @@
-.Dd June 21, 2021
+.Dd July 26, 2022
 .Dt UP 1
 .Os
 .
@@ -8,15 +8,9 @@
 .
 .Sh SYNOPSIS
 .Nm
-.Op Fl h
-.Op Ar file
-.
-.Nm
-.Fl c | t
-.Ar command
-.
-.Nm
-.Fl s
+.Op Fl c | h | s | t
+.Op Fl w Ar warn
+.Op Ar file | command
 .
 .Sh DESCRIPTION
 .Nm
@@ -65,6 +59,10 @@ Run a command with
 and
 .Xr shotty 1
 to produce an HTML file for upload.
+.It Fl w Ar warn
+Create an HTML redirect with
+.Ar warn
+in its title.
 .El
 .
 .Pp
diff --git a/bin/man1/when.1 b/bin/man1/when.1
index 0b473573..3f2735f7 100644
--- a/bin/man1/when.1
+++ b/bin/man1/when.1
@@ -1,4 +1,4 @@
-.Dd July 24, 2019
+.Dd September 19, 2022
 .Dt WHEN 1
 .Os
 .
@@ -9,6 +9,8 @@
 .Sh SYNOPSIS
 .Nm
 .Op Ar expr
+.Nm
+.Cm -
 .
 .Sh DESCRIPTION
 .Nm
@@ -18,24 +20,32 @@ If no
 is given,
 expressions are read
 from standard input.
+If
+.Cm -
+is given,
+the intervals between each named date
+and today are printed.
 .
 .Pp
 The grammar is as follows:
 .Bl -tag -width Ds
 .It Sy \&.
 Today's date.
+The empty expression is equivalent.
+.
+.It Ar name Op Sy = Ar date
+A named date.
+Names are alphanumeric including underscores.
 .
 .It Ar month Ar date Op Ar year
 A full date,
 or a date in the current year.
-.Ar month
-must be at least three letters.
+Months can be abbreviated to three letters.
 .
 .It Ar day
 A day of the week
 in the current week.
-.Ar day
-must be at least three letters.
+Days can be abbreviated to three letters.
 .
 .It Sy < Ar date
 The date one week before.
@@ -65,6 +75,14 @@ A number of months.
 A number of years.
 .El
 .
+.Sh FILES
+The file
+.Pa $XDG_CONFIG_HOME/when/dates
+or
+.Pa ~/.config/when/dates
+is read before any other expressions,
+if it exists.
+.
 .Sh EXAMPLES
 .Bl -tag -width "Dec 25 - ."
 .It Ic Dec 25 - \&.
@@ -74,3 +92,9 @@ The date next Friday.
 .It Ic \&. + 2w
 Your last day at work.
 .El
+.Pp
+Checking a milestone:
+.Bd -literal -offset indent
+$ echo 'hrt = oct 15 2021' >> ~/.config/when/dates
+$ when -hrt
+.Ed
diff --git a/bin/mdoc.l b/bin/mdoc.l
index f29b6ceb..b6deacbe 100644
--- a/bin/mdoc.l
+++ b/bin/mdoc.l
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
diff --git a/bin/modem.c b/bin/modem.c
index 2133ae08..75517159 100644
--- a/bin/modem.c
+++ b/bin/modem.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2018  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -19,7 +19,6 @@
 #include <stdlib.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
-#include <sysexits.h>
 #include <termios.h>
 #include <unistd.h>
 
@@ -46,31 +45,31 @@ int main(int argc, char *argv[]) {
 	for (int opt; 0 < (opt = getopt(argc, argv, "r:"));) {
 		switch (opt) {
 			break; case 'r': baudRate = strtoul(optarg, NULL, 10);
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
-	if (argc - optind < 1) return EX_USAGE;
+	if (argc - optind < 1) return 1;
 
 	error = tcgetattr(STDIN_FILENO, &saveTerm);
-	if (error) err(EX_IOERR, "tcgetattr");
+	if (error) err(1, "tcgetattr");
 	atexit(restoreTerm);
 
 	struct termios raw = saveTerm;
 	cfmakeraw(&raw);
 	error = tcsetattr(STDIN_FILENO, TCSADRAIN, &raw);
-	if (error) err(EX_IOERR, "tcsetattr");
+	if (error) err(1, "tcsetattr");
 
 	struct winsize window;
 	error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window);
-	if (error) err(EX_IOERR, "TIOCGWINSZ");
+	if (error) err(1, "TIOCGWINSZ");
 
 	int pty;
 	pid_t pid = forkpty(&pty, NULL, NULL, &window);
-	if (pid < 0) err(EX_OSERR, "forkpty");
+	if (pid < 0) err(1, "forkpty");
 
 	if (!pid) {
 		execvp(argv[optind], &argv[optind]);
-		err(EX_NOINPUT, "%s", argv[optind]);
+		err(1, "%s", argv[optind]);
 	}
 
 	byte c;
@@ -81,22 +80,22 @@ int main(int argc, char *argv[]) {
 	while (usleep(8 * 1000000 / baudRate), 0 < poll(fds, 2, -1)) {
 		if (fds[0].revents) {
 			ssize_t size = read(STDIN_FILENO, &c, 1);
-			if (size < 0) err(EX_IOERR, "read(%d)", STDIN_FILENO);
+			if (size < 0) err(1, "read(%d)", STDIN_FILENO);
 			size = write(pty, &c, 1);
-			if (size < 0) err(EX_IOERR, "write(%d)", pty);
+			if (size < 0) err(1, "write(%d)", pty);
 		}
 
 		if (fds[1].revents) {
 			ssize_t size = read(pty, &c, 1);
-			if (size < 0) err(EX_IOERR, "read(%d)", pty);
+			if (size < 0) err(1, "read(%d)", pty);
 			if (!size) break;
 			size = write(STDOUT_FILENO, &c, 1);
-			if (size < 0) err(EX_IOERR, "write(%d)", STDOUT_FILENO);
+			if (size < 0) err(1, "write(%d)", STDOUT_FILENO);
 		}
 	}
 
 	int status;
 	pid_t dead = waitpid(pid, &status, 0);
-	if (dead < 0) err(EX_OSERR, "waitpid");
-	return WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE;
+	if (dead < 0) err(1, "waitpid");
+	return WIFEXITED(status) ? WEXITSTATUS(status) : 1;
 }
diff --git a/bin/mtags.c b/bin/mtags.c
index 11cd9c8a..5c42f343 100644
--- a/bin/mtags.c
+++ b/bin/mtags.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -21,7 +21,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 static void escape(FILE *file, const char *str, size_t len) {
@@ -41,16 +40,16 @@ int main(int argc, char *argv[]) {
 		switch (opt) {
 			break; case 'a': append = true;
 			break; case 'f': path = optarg;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 
 	FILE *tags = fopen(path, (append ? "a" : "w"));
-	if (!tags) err(EX_CANTCREAT, "%s", path);
+	if (!tags) err(1, "%s", path);
 
 #ifdef __OpenBSD__
 	error = pledge("stdio rpath", NULL);
-	if (error) err(EX_OSERR, "pledge");
+	if (error) err(1, "pledge");
 #endif
 
 	regex_t makeFile, makeLine;
@@ -87,7 +86,7 @@ int main(int argc, char *argv[]) {
 		}
 
 		FILE *file = fopen(argv[i], "r");
-		if (!file) err(EX_NOINPUT, "%s", argv[i]);
+		if (!file) err(1, "%s", argv[i]);
 
 		while (0 < getline(&buf, &cap, file)) {
 			regmatch_t match[2];
diff --git a/bin/nudge.c b/bin/nudge.c
index 108d2459..c6247b87 100644
--- a/bin/nudge.c
+++ b/bin/nudge.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -18,7 +18,6 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
 #include <termios.h>
 #include <unistd.h>
 
@@ -39,21 +38,21 @@ int main(int argc, char *argv[]) {
 			break; case 'n': count = atoi(optarg);
 			break; case 's': shake = atoi(optarg);
 			break; case 't': delay = atoi(optarg) * 1000;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 
 	int tty = open(path, O_RDWR);
-	if (tty < 0) err(EX_OSFILE, "%s", path);
+	if (tty < 0) err(1, "%s", path);
 
 	struct termios save;
 	int error = tcgetattr(tty, &save);
-	if (error) err(EX_IOERR, "tcgetattr");
+	if (error) err(1, "tcgetattr");
 
 	struct termios raw = save;
 	cfmakeraw(&raw);
 	error = tcsetattr(tty, TCSAFLUSH, &raw);
-	if (error) err(EX_IOERR, "tcsetattr");
+	if (error) err(1, "tcsetattr");
 
 	char buf[256];
 	dprintf(tty, "\33[13t");
@@ -64,8 +63,8 @@ int main(int argc, char *argv[]) {
 	int n = sscanf(buf, "\33[3;%d;%dt", &x, &y);
 
 	error = tcsetattr(tty, TCSANOW, &save);
-	if (error) err(EX_IOERR, "tcsetattr");
-	if (n < 2) return EX_CONFIG;
+	if (error) err(1, "tcsetattr");
+	if (n < 2) return 1;
 
 	dprintf(tty, "\33[5t");
 	for (int i = 0; i < count; ++i) {
diff --git a/bin/order.y b/bin/order.y
index c2e87971..05be9838 100644
--- a/bin/order.y
+++ b/bin/order.y
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 
 #define YYSTYPE char *
 
@@ -32,7 +31,7 @@ static char *fmt(const char *format, ...) {
 	va_start(ap, format);
 	vasprintf(&str, format, ap);
 	va_end(ap);
-	if (!str) err(EX_OSERR, "vasprintf");
+	if (!str) err(1, "vasprintf");
 	return str;
 }
 
@@ -179,17 +178,17 @@ static int yylex(void) {
 }
 
 static void yyerror(const char *str) {
-	errx(EX_DATAERR, "%s", str);
+	errx(1, "%s", str);
 }
 
 int main(int argc, char *argv[]) {
 	for (int i = 1; i < argc; ++i) {
 		in = fmemopen(argv[i], strlen(argv[i]), "r");
-		if (!in) err(EX_OSERR, "fmemopen");
+		if (!in) err(1, "fmemopen");
 		yyparse();
 		fclose(in);
 	}
-	if (argc > 1) return EX_OK;
+	if (argc > 1) return 0;
 	in = stdin;
 	yyparse();
 }
diff --git a/bin/pbd.c b/bin/pbd.c
index 2fd401ae..8375fc38 100644
--- a/bin/pbd.c
+++ b/bin/pbd.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2017  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -24,27 +24,26 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 typedef unsigned char byte;
 
 static void spawn(const char *cmd, const char *arg, int dest, int src) {
 	pid_t pid = fork();
-	if (pid < 0) err(EX_OSERR, "fork");
+	if (pid < 0) err(1, "fork");
 
 	if (pid) {
 		int status;
 		pid_t dead = waitpid(pid, &status, 0);
-		if (dead < 0) err(EX_OSERR, "waitpid(%d)", pid);
+		if (dead < 0) err(1, "waitpid(%d)", pid);
 		if (status) warnx("%s: status %d", cmd, status);
 
 	} else {
 		int fd = dup2(src, dest);
-		if (fd < 0) err(EX_OSERR, "dup2");
+		if (fd < 0) err(1, "dup2");
 
 		execlp(cmd, cmd, arg, NULL);
-		err(EX_UNAVAILABLE, "%s", cmd);
+		err(127, "%s", cmd);
 	}
 }
 
@@ -52,10 +51,10 @@ static int pbd(void) {
 	int error;
 
 	int server = socket(PF_INET, SOCK_STREAM, 0);
-	if (server < 0) err(EX_OSERR, "socket");
+	if (server < 0) err(1, "socket");
 
 	error = fcntl(server, F_SETFD, FD_CLOEXEC);
-	if (error) err(EX_IOERR, "fcntl");
+	if (error) err(1, "fcntl");
 
 	struct sockaddr_in addr = {
 		.sin_family = AF_INET,
@@ -63,17 +62,17 @@ static int pbd(void) {
 		.sin_addr = { .s_addr = htonl(0x7F000001) },
 	};
 	error = bind(server, (struct sockaddr *)&addr, sizeof(addr));
-	if (error) err(EX_UNAVAILABLE, "bind");
+	if (error) err(1, "bind");
 
 	error = listen(server, 0);
-	if (error) err(EX_UNAVAILABLE, "listen");
+	if (error) err(1, "listen");
 
 	for (;;) {
 		int client = accept(server, NULL, NULL);
-		if (client < 0) err(EX_IOERR, "accept");
+		if (client < 0) err(1, "accept");
 
 		error = fcntl(client, F_SETFD, FD_CLOEXEC);
-		if (error) err(EX_IOERR, "fcntl");
+		if (error) err(1, "fcntl");
 
 		char c = 0;
 		ssize_t size = read(client, &c, 1);
@@ -91,7 +90,7 @@ static int pbd(void) {
 
 static int pbdClient(char c) {
 	int client = socket(PF_INET, SOCK_STREAM, 0);
-	if (client < 0) err(EX_OSERR, "socket");
+	if (client < 0) err(1, "socket");
 
 	struct sockaddr_in addr = {
 		.sin_family = AF_INET,
@@ -99,10 +98,10 @@ static int pbdClient(char c) {
 		.sin_addr = { .s_addr = htonl(0x7F000001) },
 	};
 	int error = connect(client, (struct sockaddr *)&addr, sizeof(addr));
-	if (error) err(EX_UNAVAILABLE, "connect");
+	if (error) err(1, "connect");
 
 	ssize_t size = write(client, &c, 1);
-	if (size < 0) err(EX_IOERR, "write");
+	if (size < 0) err(1, "write");
 
 	return client;
 }
@@ -112,29 +111,29 @@ static void copy(int out, int in) {
 	ssize_t readSize;
 	while (0 < (readSize = read(in, buf, sizeof(buf)))) {
 		ssize_t writeSize = write(out, buf, readSize);
-		if (writeSize < 0) err(EX_IOERR, "write(%d)", out);
+		if (writeSize < 0) err(1, "write(%d)", out);
 	}
-	if (readSize < 0) err(EX_IOERR, "read(%d)", in);
+	if (readSize < 0) err(1, "read(%d)", in);
 }
 
 static int pbcopy(void) {
 	int client = pbdClient('c');
 	copy(client, STDIN_FILENO);
-	return EX_OK;
+	return 0;
 }
 
 static int pbpaste(void) {
 	int client = pbdClient('p');
 	copy(STDOUT_FILENO, client);
-	return EX_OK;
+	return 0;
 }
 
 static int open1(const char *url) {
-	if (!url) return EX_USAGE;
+	if (!url) return 1;
 	int client = pbdClient('o');
 	ssize_t size = write(client, url, strlen(url));
-	if (size < 0) err(EX_IOERR, "write");
-	return EX_OK;
+	if (size < 0) err(1, "write");
+	return 0;
 }
 
 int main(int argc, char *argv[]) {
@@ -144,7 +143,7 @@ int main(int argc, char *argv[]) {
 			case 'o': return open1(optarg);
 			case 'p': return pbpaste();
 			case 's': return pbd();
-			default:  return EX_USAGE;
+			default:  return 1;
 		}
 	}
 	return pbd();
diff --git a/bin/png.h b/bin/png.h
index 15b6d13d..ec884395 100644
--- a/bin/png.h
+++ b/bin/png.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2018  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -18,7 +18,6 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
 
 static inline uint32_t pngCRCTable(uint8_t n) {
 	static uint32_t table[256];
@@ -35,7 +34,7 @@ static inline uint32_t pngCRCTable(uint8_t n) {
 static uint32_t pngCRC;
 
 static inline void pngWrite(FILE *file, const uint8_t *ptr, uint32_t len) {
-	if (!fwrite(ptr, len, 1, file)) err(EX_IOERR, "pngWrite");
+	if (!fwrite(ptr, len, 1, file)) err(1, "pngWrite");
 	for (uint32_t i = 0; i < len; ++i) {
 		pngCRC = pngCRCTable(pngCRC ^ ptr[i]) ^ (pngCRC >> 8);
 	}
diff --git a/bin/pngo.c b/bin/pngo.c
index ba90889a..e2ad3837 100644
--- a/bin/pngo.c
+++ b/bin/pngo.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018, 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2018, 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 #include <zlib.h>
 
@@ -35,14 +34,14 @@ static uint32_t crc;
 
 static void pngRead(void *ptr, size_t len, const char *desc) {
 	size_t n = fread(ptr, len, 1, file);
-	if (!n && ferror(file)) err(EX_IOERR, "%s", path);
-	if (!n) errx(EX_DATAERR, "%s: missing %s", path, desc);
+	if (!n && ferror(file)) err(1, "%s", path);
+	if (!n) errx(1, "%s: missing %s", path, desc);
 	crc = crc32(crc, ptr, len);
 }
 
 static void pngWrite(const void *ptr, size_t len) {
 	size_t n = fwrite(ptr, len, 1, file);
-	if (!n) err(EX_IOERR, "%s", path);
+	if (!n) err(1, "%s", path);
 	crc = crc32(crc, ptr, len);
 }
 
@@ -52,7 +51,7 @@ static void sigRead(void) {
 	uint8_t sig[sizeof(Sig)];
 	pngRead(sig, sizeof(sig), "signature");
 	if (memcmp(sig, Sig, sizeof(sig))) {
-		errx(EX_DATAERR, "%s: invalid signature", path);
+		errx(1, "%s: invalid signature", path);
 	}
 }
 
@@ -96,10 +95,7 @@ static void crcRead(void) {
 	uint32_t expect = crc;
 	uint32_t actual = u32Read("CRC32");
 	if (actual == expect) return;
-	errx(
-		EX_DATAERR, "%s: expected CRC32 %08X, found %08X",
-		path, expect, actual
-	);
+	errx(1, "%s: expected CRC32 %08X, found %08X", path, expect, actual);
 }
 
 static void crcWrite(void) {
@@ -108,7 +104,7 @@ static void crcWrite(void) {
 
 static void chunkSkip(struct Chunk chunk) {
 	if (!(chunk.type[0] & 0x20)) {
-		errx(EX_CONFIG, "%s: unsupported critical chunk %s", path, chunk.type);
+		errx(1, "%s: unsupported critical chunk %s", path, chunk.type);
 	}
 	uint8_t buf[4096];
 	while (chunk.len > sizeof(buf)) {
@@ -181,7 +177,7 @@ static void headerPrint(void) {
 static void headerRead(struct Chunk chunk) {
 	if (chunk.len != HeaderLen) {
 		errx(
-			EX_DATAERR, "%s: expected %s length %" PRIu32 ", found %" PRIu32,
+			1, "%s: expected %s length %" PRIu32 ", found %" PRIu32,
 			path, chunk.type, (uint32_t)HeaderLen, chunk.len
 		);
 	}
@@ -195,8 +191,8 @@ static void headerRead(struct Chunk chunk) {
 	crcRead();
 	recalc();
 
-	if (!header.width) errx(EX_DATAERR, "%s: invalid width 0", path);
-	if (!header.height) errx(EX_DATAERR, "%s: invalid height 0", path);
+	if (!header.width) errx(1, "%s: invalid width 0", path);
+	if (!header.height) errx(1, "%s: invalid height 0", path);
 	static const struct {
 		uint8_t color;
 		uint8_t depth;
@@ -228,28 +224,21 @@ static void headerRead(struct Chunk chunk) {
 	}
 	if (!valid) {
 		errx(
-			EX_DATAERR,
-			"%s: invalid color type %" PRIu8 " and bit depth %" PRIu8,
+			1, "%s: invalid color type %" PRIu8 " and bit depth %" PRIu8,
 			path, header.color, header.depth
 		);
 	}
 	if (header.compression != Deflate) {
 		errx(
-			EX_DATAERR, "%s: invalid compression method %" PRIu8,
+			1, "%s: invalid compression method %" PRIu8,
 			path, header.compression
 		);
 	}
 	if (header.filter != Adaptive) {
-		errx(
-			EX_DATAERR, "%s: invalid filter method %" PRIu8,
-			path, header.filter
-		);
+		errx(1, "%s: invalid filter method %" PRIu8, path, header.filter);
 	}
 	if (header.interlace > Adam7) {
-		errx(
-			EX_DATAERR, "%s: invalid interlace method %" PRIu8,
-			path, header.interlace
-		);
+		errx(1, "%s: invalid interlace method %" PRIu8, path, header.interlace);
 	}
 
 	if (verbose) headerPrint();
@@ -331,16 +320,13 @@ static void transCompact(void) {
 static void palRead(struct Chunk chunk) {
 	if (chunk.len % 3) {
 		errx(
-			EX_DATAERR, "%s: %s length %" PRIu32 " not divisible by 3",
+			1, "%s: %s length %" PRIu32 " not divisible by 3",
 			path, chunk.type, chunk.len
 		);
 	}
 	pal.len = chunk.len / 3;
 	if (pal.len > 256) {
-		errx(
-			EX_DATAERR, "%s: %s length %" PRIu32 " > 256",
-			path, chunk.type, pal.len
-		);
+		errx(1, "%s: %s length %" PRIu32 " > 256", path, chunk.type, pal.len);
 	}
 	pngRead(pal.rgb, chunk.len, "palette data");
 	crcRead();
@@ -362,10 +348,7 @@ static void palWrite(void) {
 static void transRead(struct Chunk chunk) {
 	trans.len = chunk.len;
 	if (trans.len > 256) {
-		errx(
-			EX_DATAERR, "%s: %s length %" PRIu32 " > 256",
-			path, chunk.type, trans.len
-		);
+		errx(1, "%s: %s length %" PRIu32 " > 256", path, chunk.type, trans.len);
 	}
 	pngRead(trans.a, chunk.len, "transparency data");
 	crcRead();
@@ -388,7 +371,7 @@ static uint8_t *data;
 
 static void dataAlloc(void) {
 	data = malloc(dataLen);
-	if (!data) err(EX_OSERR, "malloc");
+	if (!data) err(1, "malloc");
 }
 
 static const char *humanize(size_t n) {
@@ -408,15 +391,15 @@ static void dataRead(struct Chunk chunk) {
 
 	z_stream stream = { .next_out = data, .avail_out = dataLen };
 	int error = inflateInit(&stream);
-	if (error != Z_OK) errx(EX_SOFTWARE, "inflateInit: %s", stream.msg);
+	if (error != Z_OK) errx(1, "inflateInit: %s", stream.msg);
 
 	for (;;) {
 		if (strcmp(chunk.type, "IDAT")) {
-			errx(EX_DATAERR, "%s: missing IDAT chunk", path);
+			errx(1, "%s: missing IDAT chunk", path);
 		}
 
 		uint8_t *idat = malloc(chunk.len);
-		if (!idat) err(EX_OSERR, "malloc");
+		if (!idat) err(1, "malloc");
 
 		pngRead(idat, chunk.len, "image data");
 		crcRead();
@@ -428,7 +411,7 @@ static void dataRead(struct Chunk chunk) {
 
 		if (error == Z_STREAM_END) break;
 		if (error != Z_OK) {
-			errx(EX_DATAERR, "%s: inflate: %s", path, stream.msg);
+			errx(1, "%s: inflate: %s", path, stream.msg);
 		}
 
 		chunk = chunkRead();
@@ -436,7 +419,7 @@ static void dataRead(struct Chunk chunk) {
 	inflateEnd(&stream);
 	if ((size_t)stream.total_out != dataLen) {
 		errx(
-			EX_DATAERR, "%s: expected data length %zu, found %zu",
+			1, "%s: expected data length %zu, found %zu",
 			path, dataLen, (size_t)stream.total_out
 		);
 	}
@@ -461,11 +444,11 @@ static void dataWrite(void) {
 	int error = deflateInit2(
 		&stream, Z_BEST_COMPRESSION, Z_DEFLATED, 15, 8, Z_FILTERED
 	);
-	if (error != Z_OK) errx(EX_SOFTWARE, "deflateInit2: %s", stream.msg);
+	if (error != Z_OK) errx(1, "deflateInit2: %s", stream.msg);
 
 	uLong bound = deflateBound(&stream, dataLen);
 	uint8_t *buf = malloc(bound);
-	if (!buf) err(EX_OSERR, "malloc");
+	if (!buf) err(1, "malloc");
 
 	stream.next_out = buf;
 	stream.avail_out = bound;
@@ -566,7 +549,7 @@ static void dataFilter(void) {
 	uint8_t *filter[FilterCap];
 	for (enum Filter i = None; i < FilterCap; ++i) {
 		filter[i] = malloc(lineLen);
-		if (!filter[i]) err(EX_OSERR, "malloc");
+		if (!filter[i]) err(1, "malloc");
 	}
 	for (uint32_t y = header.height-1; y < header.height; --y) {
 		uint32_t heuristic[FilterCap] = {0};
@@ -838,7 +821,7 @@ static void optimize(const char *inPath, const char *outPath) {
 	if (inPath) {
 		path = inPath;
 		file = fopen(path, "r");
-		if (!file) err(EX_NOINPUT, "%s", path);
+		if (!file) err(1, "%s", path);
 	} else {
 		path = "stdin";
 		file = stdin;
@@ -847,11 +830,11 @@ static void optimize(const char *inPath, const char *outPath) {
 	sigRead();
 	struct Chunk ihdr = chunkRead();
 	if (strcmp(ihdr.type, "IHDR")) {
-		errx(EX_DATAERR, "%s: expected IHDR, found %s", path, ihdr.type);
+		errx(1, "%s: expected IHDR, found %s", path, ihdr.type);
 	}
 	headerRead(ihdr);
 	if (header.interlace != Progressive) {
-		errx(EX_CONFIG, "%s: unsupported interlacing", path);
+		errx(1, "%s: unsupported interlacing", path);
 	}
 
 	palClear();
@@ -888,10 +871,10 @@ static void optimize(const char *inPath, const char *outPath) {
 		if (outPath == inPath) {
 			snprintf(buf, sizeof(buf), "%so", outPath);
 			file = fopen(buf, "wx");
-			if (!file) err(EX_CANTCREAT, "%s", buf);
+			if (!file) err(1, "%s", buf);
 		} else {
 			file = fopen(path, "w");
-			if (!file) err(EX_CANTCREAT, "%s", outPath);
+			if (!file) err(1, "%s", outPath);
 		}
 	} else {
 		path = "stdout";
@@ -907,11 +890,11 @@ static void optimize(const char *inPath, const char *outPath) {
 	dataWrite();
 	free(data);
 	int error = fclose(file);
-	if (error) err(EX_IOERR, "%s", path);
+	if (error) err(1, "%s", path);
 
 	if (outPath && outPath == inPath) {
 		error = rename(buf, outPath);
-		if (error) err(EX_CANTCREAT, "%s", outPath);
+		if (error) err(1, "%s", outPath);
 	}
 }
 
@@ -927,7 +910,7 @@ int main(int argc, char *argv[]) {
 			break; case 'g': discardColor = true;
 			break; case 'o': outPath = optarg;
 			break; case 'v': verbose = true;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 
diff --git a/bin/psf2png.c b/bin/psf2png.c
index 1aaa8635..aeb975b3 100644
--- a/bin/psf2png.c
+++ b/bin/psf2png.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2018  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -19,7 +19,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 #include "png.h"
@@ -37,17 +36,17 @@ int main(int argc, char *argv[]) {
 			break; case 'c': cols = strtoul(optarg, NULL, 0);
 			break; case 'f': fg = strtoul(optarg, NULL, 16);
 			break; case 's': str = optarg;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 	if (!cols && str) cols = strlen(str);
-	if (!cols) return EX_USAGE;
+	if (!cols) return 1;
 
 	const char *path = NULL;
 	if (optind < argc) path = argv[optind];
 	
 	FILE *file = path ? fopen(path, "r") : stdin;
-	if (!file) err(EX_NOINPUT, "%s", path);
+	if (!file) err(1, "%s", path);
 	if (!path) path = "(stdin)";
 
 	struct {
@@ -63,15 +62,15 @@ int main(int argc, char *argv[]) {
 		} glyph;
 	} header;
 	size_t len = fread(&header, sizeof(header), 1, file);
-	if (ferror(file)) err(EX_IOERR, "%s", path);
-	if (len < 1) errx(EX_DATAERR, "%s: truncated header", path);
+	if (ferror(file)) err(1, "%s", path);
+	if (len < 1) errx(1, "%s: truncated header", path);
 
 	uint32_t widthBytes = (header.glyph.width + 7) / 8;
 	uint8_t glyphs[header.glyph.len][header.glyph.height][widthBytes];
 	len = fread(glyphs, header.glyph.size, header.glyph.len, file);
-	if (ferror(file)) err(EX_IOERR, "%s", path);
+	if (ferror(file)) err(1, "%s", path);
 	if (len < header.glyph.len) {
-		errx(EX_DATAERR, "%s: truncated glyphs", path);
+		errx(1, "%s: truncated glyphs", path);
 	}
 	fclose(file);
 
diff --git a/bin/ptee.c b/bin/ptee.c
index 8374bd8f..c4749d62 100644
--- a/bin/ptee.c
+++ b/bin/ptee.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -24,7 +24,6 @@
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <sys/wait.h>
-#include <sysexits.h>
 #include <termios.h>
 #include <unistd.h>
 
@@ -52,35 +51,35 @@ int main(int argc, char *argv[]) {
 	for (int opt; 0 < (opt = getopt(argc, argv, "t:"));) {
 		switch (opt) {
 			break; case 't': timer = atoi(optarg);
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 	argc -= optind;
 	argv += optind;
 
-	if (argc < 1) return EX_USAGE;
-	if (isatty(STDOUT_FILENO)) errx(EX_USAGE, "stdout is not redirected");
+	if (argc < 1) return 1;
+	if (isatty(STDOUT_FILENO)) errx(1, "stdout is not redirected");
 
 	int error = tcgetattr(STDIN_FILENO, &saveTerm);
-	if (error) err(EX_IOERR, "tcgetattr");
+	if (error) err(1, "tcgetattr");
 	atexit(restoreTerm);
 
 	struct termios raw = saveTerm;
 	cfmakeraw(&raw);
 	error = tcsetattr(STDIN_FILENO, TCSADRAIN, &raw);
-	if (error) err(EX_IOERR, "tcsetattr");
+	if (error) err(1, "tcsetattr");
 
 	struct winsize window;
 	error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window);
-	if (error) err(EX_IOERR, "ioctl");
+	if (error) err(1, "ioctl");
 
 	int pty;
 	pid_t pid = forkpty(&pty, NULL, NULL, &window);
-	if (pid < 0) err(EX_OSERR, "forkpty");
+	if (pid < 0) err(1, "forkpty");
 
 	if (!pid) {
 		execvp(argv[0], argv);
-		err(EX_NOINPUT, "%s", argv[0]);
+		err(1, "%s", argv[0]);
 	}
 
 	if (timer) {
@@ -103,17 +102,17 @@ int main(int argc, char *argv[]) {
 	};
 	for (;;) {
 		int nfds = poll(fds, 2, -1);
-		if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll");
+		if (nfds < 0 && errno != EINTR) err(1, "poll");
 
 		if (nfds < 0) {
 			ssize_t wlen = write(STDOUT_FILENO, mc, sizeof(mc) - 1);
-			if (wlen < 0) err(EX_IOERR, "write");
+			if (wlen < 0) err(1, "write");
 			continue;
 		}
 
 		if (fds[0].revents & POLLIN) {
 			ssize_t rlen = read(STDIN_FILENO, buf, sizeof(buf));
-			if (rlen < 0) err(EX_IOERR, "read");
+			if (rlen < 0) err(1, "read");
 
 			if (rlen == 1 && buf[0] == CTRL('Q')) {
 				stop ^= true;
@@ -122,30 +121,30 @@ int main(int argc, char *argv[]) {
 
 			if (rlen == 1 && buf[0] == CTRL('S')) {
 				ssize_t wlen = write(STDOUT_FILENO, mc, sizeof(mc) - 1);
-				if (wlen < 0) err(EX_IOERR, "write");
+				if (wlen < 0) err(1, "write");
 				continue;
 			}
 
 			ssize_t wlen = write(pty, buf, rlen);
-			if (wlen < 0) err(EX_IOERR, "write");
+			if (wlen < 0) err(1, "write");
 		}
 
 		if (fds[1].revents & POLLIN) {
 			ssize_t rlen = read(pty, buf, sizeof(buf));
-			if (rlen < 0) err(EX_IOERR, "read");
+			if (rlen < 0) err(1, "read");
 
 			ssize_t wlen = write(STDIN_FILENO, buf, rlen);
-			if (wlen < 0) err(EX_IOERR, "write");
+			if (wlen < 0) err(1, "write");
 
 			if (!stop) {
 				wlen = write(STDOUT_FILENO, buf, rlen);
-				if (wlen < 0) err(EX_IOERR, "write");
+				if (wlen < 0) err(1, "write");
 			}
 		}
 
 		int status;
 		pid_t dead = waitpid(pid, &status, WNOHANG);
-		if (dead < 0) err(EX_OSERR, "waitpid");
-		if (dead) return WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE;
+		if (dead < 0) err(1, "waitpid");
+		if (dead) return WIFEXITED(status) ? WEXITSTATUS(status) : 1;
 	}
 }
diff --git a/bin/qf.c b/bin/qf.c
new file mode 100644
index 00000000..afa7eced
--- /dev/null
+++ b/bin/qf.c
@@ -0,0 +1,293 @@
+/* Copyright (C) 2022  June McEnroe <june@causal.agency>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <curses.h>
+#include <err.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+enum Type {
+	File,
+	Match,
+	Context,
+	Text,
+};
+
+struct Line {
+	enum Type type;
+	char *path;
+	unsigned nr;
+	char *text;
+	regmatch_t match;
+};
+
+static struct {
+	struct Line *ptr;
+	size_t len, cap;
+} lines;
+
+static void push(struct Line line) {
+	if (lines.len == lines.cap) {
+		lines.cap = (lines.cap ? lines.cap * 2 : 256);
+		lines.ptr = realloc(lines.ptr, sizeof(*lines.ptr) * lines.cap);
+		if (!lines.ptr) err(1, "realloc");
+	}
+	lines.ptr[lines.len++] = line;
+}
+
+static const char *pattern;
+static regex_t regex;
+
+static void parse(struct Line line) {
+	line.path = strsep(&line.text, ":");
+	if (!line.text) {
+		line.type = Text;
+		line.text = line.path;
+		if (lines.len) line.path = lines.ptr[lines.len-1].path;
+		push(line);
+		return;
+	}
+	char *rest;
+	line.nr = strtoul(line.text, &rest, 10);
+	struct Line prev = {0};
+	if (lines.len) prev = lines.ptr[lines.len-1];
+	if (!prev.path || strcmp(line.path, prev.path)) {
+		if (lines.len) push((struct Line) { .type = Text, .text = " " });
+		line.type = File;
+		push(line);
+	}
+	if (rest > line.text && rest[0] == ':') {
+		line.type = Match;
+		line.text = &rest[1];
+	} else if (rest > line.text && rest[0] == '-') {
+		line.type = Context;
+		line.text = &rest[1];
+	} else {
+		line.type = Text;
+	}
+	if (line.type == Match && pattern) {
+		regexec(&regex, line.text, 1, &line.match, 0);
+	}
+	push(line);
+}
+
+enum {
+	Path = 1,
+	Number = 2,
+	Highlight = 3,
+};
+
+static void curse(void) {
+	set_term(newterm(NULL, stdout, stderr));
+	cbreak();
+	noecho();
+	nodelay(stdscr, true);
+	TABSIZE = 4;
+	curs_set(0);
+	start_color();
+	use_default_colors();
+	init_pair(Path, COLOR_GREEN, -1);
+	init_pair(Number, COLOR_YELLOW, -1);
+	init_pair(Highlight, COLOR_MAGENTA, -1);
+}
+
+static size_t top;
+static size_t cur;
+static bool reading = true;
+
+static void draw(void) {
+	int y = 0, x = 0;
+	for (int i = 0; i < LINES; ++i) {
+		move(i, 0);
+		clrtoeol();
+		if (top + i >= lines.len) {
+			addstr(reading ? "..." : !lines.len ? "No results" : "");
+			break;
+		}
+		struct Line line = lines.ptr[top + i];
+		if (top + i == cur) {
+			getyx(stdscr, y, x);
+			attron(A_REVERSE);
+		} else {
+			attroff(A_REVERSE);
+		}
+		switch (line.type) {
+			break; case File: {
+				color_set(Path, NULL);
+				addstr(line.path);
+				color_set(0, NULL);
+			}
+			break; case Match: {
+				color_set(Number, NULL);
+				printw("%u", line.nr);
+				color_set(0, NULL);
+				addch(':');
+				if (line.match.rm_so == line.match.rm_eo) {
+					addstr(line.text);
+					break;
+				}
+				addnstr(line.text, line.match.rm_so);
+				color_set(Highlight, NULL);
+				addnstr(
+					&line.text[line.match.rm_so],
+					line.match.rm_eo - line.match.rm_so
+				);
+				color_set(0, NULL);
+				addstr(&line.text[line.match.rm_eo]);
+			}
+			break; case Context: {
+				color_set(Number, NULL);
+				printw("%u", line.nr);
+				color_set(0, NULL);
+				addch('-');
+				addstr(line.text);
+			}
+			break; case Text: addstr(line.text);
+		}
+	}
+	move(y, x);
+	refresh();
+}
+
+static void edit(struct Line line) {
+	char cmd[32];
+	snprintf(cmd, sizeof(cmd), "+%u", (line.nr ? line.nr : 1));
+	const char *editor = getenv("EDITOR");
+	if (!editor) editor = "vi";
+	pid_t pid = fork();
+	if (pid < 0) err(1, "fork");
+	if (!pid) {
+		dup2(STDERR_FILENO, STDIN_FILENO);
+		execlp(editor, editor, cmd, line.path, NULL);
+		err(127, "%s", editor);
+	}
+	int status;
+	pid = waitpid(pid, &status, 0);
+	if (pid < 0) err(1, "waitpid");
+}
+
+static void toPrev(enum Type type) {
+	if (!cur) return;
+	size_t prev = cur - 1;
+	while (prev && lines.ptr[prev].type != type) {
+		prev--;
+	}
+	if (lines.ptr[prev].type == type) {
+		cur = prev;
+	}
+}
+
+static void toNext(enum Type type) {
+	size_t next = cur + 1;
+	while (next < lines.len && lines.ptr[next].type != type) {
+		next++;
+	}
+	if (next < lines.len && lines.ptr[next].type == type) {
+		cur = next;
+	}
+}
+
+static void input(void) {
+	char ch;
+	while (ERR != (ch = getch())) {
+		switch (ch) {
+			break; case '\n': {
+				if (lines.ptr[cur].type == Text) break;
+				endwin();
+				edit(lines.ptr[cur]);
+				refresh();
+			}
+			break; case '{': toPrev(File);
+			break; case '}': toNext(File);
+			break; case 'G': cur = lines.len - 1;
+			break; case 'N': toPrev(Match);
+			break; case 'g': cur = 0;
+			break; case 'j': if (cur + 1 < lines.len) cur++;
+			break; case 'k': if (cur) cur--;
+			break; case 'n': toNext(Match);
+			break; case 'q': {
+				endwin();
+				exit(0);
+			}
+			break; case 'r': clearok(stdscr, true);
+		}
+	}
+	if (cur < top) top = cur;
+	if (cur >= top + LINES) top = cur - LINES + 1;
+}
+
+int main(int argc, char *argv[]) {
+	if (isatty(STDIN_FILENO)) errx(1, "no input");
+	if (argc > 1) {
+		pattern = argv[1];
+		int flags = REG_EXTENDED | REG_ICASE;
+		for (const char *ch = pattern; *ch; ++ch) {
+			if (isupper(*ch)) {
+				flags &= ~REG_ICASE;
+				break;
+			}
+		}
+		int error = regcomp(&regex, pattern, flags);
+		if (error) errx(1, "invalid pattern");
+	}
+	curse();
+	draw();
+	struct pollfd fds[2] = {
+		{ .fd = STDERR_FILENO, .events = POLLIN },
+		{ .fd = STDIN_FILENO, .events = POLLIN },
+	};
+	size_t len = 0;
+	size_t cap = 4096;
+	char *buf = malloc(cap);
+	if (!buf) err(1, "malloc");
+	while (poll(fds, (reading ? 2 : 1), -1)) {
+		if (fds[0].revents) {
+			input();
+		}
+		if (reading && fds[1].revents) {
+			ssize_t n = read(fds[1].fd, &buf[len], cap - len);
+			if (n < 0) err(1, "read");
+			if (!n) reading = false;
+			len += n;
+			char *ptr = buf;
+			for (
+				char *nl;
+				(nl = memchr(ptr, '\n', &buf[len] - ptr));
+				ptr = &nl[1]
+			) {
+				struct Line line = { .text = strndup(ptr, nl - ptr) };
+				if (!line.text) err(1, "strndup");
+				parse(line);
+			}
+			len -= ptr - buf;
+			memmove(buf, ptr, len);
+			if (len == cap) {
+				cap *= 2;
+				buf = realloc(buf, cap);
+				if (!buf) err(1, "realloc");
+			}
+		}
+		draw();
+	}
+	err(1, "poll");
+}
diff --git a/bin/quick.c b/bin/quick.c
index edf35a3b..96f29eb0 100644
--- a/bin/quick.c
+++ b/bin/quick.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -26,13 +26,12 @@
 #include <strings.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 static void request(int sock, char *argv[]) {
 	struct pollfd pfd = { .fd = sock, .events = POLLIN };
 	int nfds = poll(&pfd, 1, -1);
-	if (nfds < 0) err(EX_OSERR, "poll");
+	if (nfds < 0) err(1, "poll");
 
 	char buf[4096];
 	ssize_t len = recv(sock, buf, sizeof(buf)-1, MSG_PEEK);
@@ -89,7 +88,7 @@ static void request(int sock, char *argv[]) {
 
 	dprintf(sock, "HTTP/1.1 200 OK\nConnection: close\n");
 	pid_t pid = fork();
-	if (pid < 0) err(EX_OSERR, "fork");
+	if (pid < 0) err(1, "fork");
 	if (!pid) {
 		dup2(sock, STDIN_FILENO);
 		dup2(sock, STDOUT_FILENO);
@@ -100,7 +99,7 @@ static void request(int sock, char *argv[]) {
 
 	int status;
 	pid = wait(&status);
-	if (pid < 0) err(EX_OSERR, "wait");
+	if (pid < 0) err(1, "wait");
 	if (WIFEXITED(status) && WEXITSTATUS(status)) {
 		warnx("%s exited %d", argv[0], WEXITSTATUS(status));
 	} else if (WIFSIGNALED(status)) {
@@ -113,13 +112,13 @@ int main(int argc, char *argv[]) {
 	for (int opt; 0 < (opt = getopt(argc, argv, "p:"));) {
 		switch (opt) {
 			break; case 'p': port = atoi(optarg);
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
-	if (optind == argc) errx(EX_USAGE, "script required");
+	if (optind == argc) errx(1, "script required");
 
 	int server = socket(AF_INET, SOCK_STREAM, 0);
-	if (server < 0) err(EX_OSERR, "socket");
+	if (server < 0) err(1, "socket");
 	fcntl(server, F_SETFD, FD_CLOEXEC);
 
 	int on = 1;
@@ -135,7 +134,7 @@ int main(int argc, char *argv[]) {
 		|| bind(server, (struct sockaddr *)&addr, addrlen)
 		|| getsockname(server, (struct sockaddr *)&addr, &addrlen)
 		|| listen(server, -1);
-	if (error) err(EX_UNAVAILABLE, "%hd", port);
+	if (error) err(1, "%hd", port);
 
 	char host[NI_MAXHOST], serv[NI_MAXSERV];
 	error = getnameinfo(
@@ -143,7 +142,7 @@ int main(int argc, char *argv[]) {
 		host, sizeof(host), serv, sizeof(serv),
 		NI_NOFQDN | NI_NUMERICSERV
 	);
-	if (error) errx(EX_UNAVAILABLE, "getnameinfo: %s", gai_strerror(error));
+	if (error) errx(1, "getnameinfo: %s", gai_strerror(error));
 	printf("http://%s:%s/\n", host, serv);
 	fflush(stdout);
 
@@ -159,5 +158,5 @@ int main(int argc, char *argv[]) {
 		fcntl(sock, F_SETFD, FD_CLOEXEC);
 		request(sock, &argv[optind]);
 	}
-	err(EX_IOERR, "accept");
+	err(1, "accept");
 }
diff --git a/bin/relay.c b/bin/relay.c
index aa7913c9..a1a134d4 100644
--- a/bin/relay.c
+++ b/bin/relay.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -35,7 +35,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
-#include <sysexits.h>
 #include <tls.h>
 #include <unistd.h>
 
@@ -47,7 +46,7 @@ static void clientWrite(struct tls *client, const char *ptr, size_t len) {
 	while (len) {
 		ssize_t ret = tls_write(client, ptr, len);
 		if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue;
-		if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(client));
+		if (ret < 0) errx(1, "tls_write: %s", tls_error(client));
 		ptr += ret;
 		len -= ret;
 	}
@@ -59,7 +58,7 @@ static void clientFormat(struct tls *client, const char *format, ...) {
 	va_start(ap, format);
 	int len = vsnprintf(buf, sizeof(buf), format, ap);
 	va_end(ap);
-	if ((size_t)len > sizeof(buf) - 1) errx(EX_DATAERR, "message too large");
+	if ((size_t)len > sizeof(buf) - 1) errx(1, "message too large");
 	clientWrite(client, buf, len);
 }
 
@@ -67,7 +66,7 @@ static void clientHandle(struct tls *client, const char *chan, char *line) {
 	char *prefix = NULL;
 	if (line[0] == ':') {
 		prefix = strsep(&line, " ") + 1;
-		if (!line) errx(EX_PROTOCOL, "unexpected eol");
+		if (!line) errx(1, "unexpected eol");
 	}
 
 	char *command = strsep(&line, " ");
@@ -78,14 +77,14 @@ static void clientHandle(struct tls *client, const char *chan, char *line) {
 	}
 	if (strcmp(command, "PRIVMSG") && strcmp(command, "NOTICE")) return;
 
-	if (!prefix) errx(EX_PROTOCOL, "message without prefix");
+	if (!prefix) errx(1, "message without prefix");
 	char *nick = strsep(&prefix, "!");
 
-	if (!line) errx(EX_PROTOCOL, "message without destination");
+	if (!line) errx(1, "message without destination");
 	char *dest = strsep(&line, " ");
 	if (strcmp(dest, chan)) return;
 
-	if (!line || line[0] != ':') errx(EX_PROTOCOL, "message without message");
+	if (!line || line[0] != ':') errx(1, "message without message");
 	line = &line[1];
 
 	if (!strncmp(line, "\1ACTION ", 8)) {
@@ -102,14 +101,14 @@ static void clientHandle(struct tls *client, const char *chan, char *line) {
 #ifdef __FreeBSD__
 static void limit(int fd, const cap_rights_t *rights) {
 	int error = cap_rights_limit(fd, rights);
-	if (error) err(EX_OSERR, "cap_rights_limit");
+	if (error) err(1, "cap_rights_limit");
 }
 #endif
 
 int main(int argc, char *argv[]) {
 	int error;
 
-	if (argc < 5) return EX_USAGE;
+	if (argc < 5) return 1;
 	const char *host = argv[1];
 	const char *port = argv[2];
 	const char *nick = argv[3];
@@ -119,18 +118,18 @@ int main(int argc, char *argv[]) {
 	signal(SIGPIPE, SIG_IGN);
 
 	struct tls_config *config = tls_config_new();
-	if (!config) errx(EX_SOFTWARE, "tls_config_new");
+	if (!config) errx(1, "tls_config_new");
 
 	error = tls_config_set_ciphers(config, "compat");
 	if (error) {
-		errx(EX_SOFTWARE, "tls_config_set_ciphers: %s", tls_config_error(config));
+		errx(1, "tls_config_set_ciphers: %s", tls_config_error(config));
 	}
 
 	struct tls *client = tls_client();
-	if (!client) errx(EX_SOFTWARE, "tls_client");
+	if (!client) errx(1, "tls_client");
 
 	error = tls_configure(client, config);
-	if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client));
+	if (error) errx(1, "tls_configure: %s", tls_error(client));
 	tls_config_free(config);
 
 	struct addrinfo *head;
@@ -140,12 +139,12 @@ int main(int argc, char *argv[]) {
 		.ai_protocol = IPPROTO_TCP,
 	};
 	error = getaddrinfo(host, port, &hints, &head);
-	if (error) errx(EX_NOHOST, "getaddrinfo: %s", gai_strerror(error));
+	if (error) errx(1, "getaddrinfo: %s", gai_strerror(error));
 
 	int sock = -1;
 	for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
 		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-		if (sock < 0) err(EX_OSERR, "socket");
+		if (sock < 0) err(1, "socket");
 
 		error = connect(sock, ai->ai_addr, ai->ai_addrlen);
 		if (!error) break;
@@ -153,15 +152,15 @@ int main(int argc, char *argv[]) {
 		close(sock);
 		sock = -1;
 	}
-	if (sock < 0) err(EX_UNAVAILABLE, "connect");
+	if (sock < 0) err(1, "connect");
 	freeaddrinfo(head);
 
 	error = tls_connect_socket(client, sock, host);
-	if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(client));
+	if (error) errx(1, "tls_connect: %s", tls_error(client));
 
 #ifdef __FreeBSD__
 	error = cap_enter();
-	if (error) err(EX_OSERR, "cap_enter");
+	if (error) err(1, "cap_enter");
 
 	cap_rights_t rights;
 	cap_rights_init(&rights, CAP_WRITE);
@@ -190,7 +189,7 @@ int main(int argc, char *argv[]) {
 	while (0 < poll(fds, 2, -1)) {
 		if (fds[0].revents) {
 			ssize_t len = getline(&input, &cap, stdin);
-			if (len < 0) err(EX_IOERR, "getline");
+			if (len < 0) err(1, "getline");
 			input[len - 1] = '\0';
 			clientFormat(client, "NOTICE %s :%s\r\n", chan, input);
 		}
@@ -198,8 +197,8 @@ int main(int argc, char *argv[]) {
 
 		ssize_t read = tls_read(client, &buf[len], sizeof(buf) - len);
 		if (read == TLS_WANT_POLLIN || read == TLS_WANT_POLLOUT) continue;
-		if (read < 0) errx(EX_IOERR, "tls_read: %s", tls_error(client));
-		if (!read) return EX_UNAVAILABLE;
+		if (read < 0) errx(1, "tls_read: %s", tls_error(client));
+		if (!read) return 1;
 		len += read;
 
 		char *crlf;
@@ -214,5 +213,5 @@ int main(int argc, char *argv[]) {
 		len -= line - buf;
 		memmove(buf, line, len);
 	}
-	err(EX_IOERR, "poll");
+	err(1, "poll");
 }
diff --git a/bin/scheme.c b/bin/scheme.c
index 33fd8b60..82539ba2 100644
--- a/bin/scheme.c
+++ b/bin/scheme.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018, 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2018, 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -19,7 +19,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 #include "png.h"
@@ -263,14 +262,14 @@ int main(int argc, char *argv[]) {
 			break; case 'm': output = outputMintty;
 			break; case 'p': {
 				uint p = strtoul(optarg, NULL, 0);
-				if (p >= SchemeLen) return EX_USAGE;
+				if (p >= SchemeLen) return 1;
 				hsv = &scheme[p];
 				len = 1;
 			}
 			break; case 's': output = outputCSS;
 			break; case 't': len = SchemeLen;
 			break; case 'x': output = outputRGB;
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 
diff --git a/bin/sh.l b/bin/sh.l
index 9664b009..8f0f7723 100644
--- a/bin/sh.l
+++ b/bin/sh.l
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -36,7 +36,7 @@ static int pop(void) {
 }
 %}
 
-%s Param Command Arith Backtick
+%s Param Command Arith Backtick Subshell
 %x DQuote HereDocDel HereDoc HereDocLit
 
 word [[:alnum:]_.-]+
@@ -51,7 +51,7 @@ reserved [!{}]|else|do|elif|for|done|fi|then|until|while|if|case|esac
 
 "\\". { return Escape; }
 
-<INITIAL,DQuote,HereDoc,Param,Command,Arith>{
+<INITIAL,DQuote,HereDoc,Param,Command,Arith,Subshell>{
 	"$"[*@#?$!0-9-] |
 	"$"[_[:alpha:][_[:alnum:]]* |
 	"${"[#]?{param}"}" {
@@ -73,6 +73,10 @@ reserved [!{}]|else|do|elif|for|done|fi|then|until|while|if|case|esac
 		BEGIN(push(Backtick));
 		return Subst;
 	}
+	"(" {
+		BEGIN(push(Subshell));
+		return Normal;
+	}
 }
 <Param>"}" |
 <Command>")" |
@@ -81,6 +85,10 @@ reserved [!{}]|else|do|elif|for|done|fi|then|until|while|if|case|esac
 	BEGIN(pop());
 	return Subst;
 }
+<Subshell>")" {
+	BEGIN(pop());
+	return Normal;
+}
 
 "\n" {
 	first = true;
diff --git a/bin/shotty.l b/bin/shotty.l
index ff78d241..b6d54eee 100644
--- a/bin/shotty.l
+++ b/bin/shotty.l
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019, 2021  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019, 2021  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -26,7 +26,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
-#include <sysexits.h>
 #include <unistd.h>
 #include <wchar.h>
 
@@ -181,13 +180,13 @@ ESC \x1B
 		| (wchar_t)(yytext[1] & 0x3F);
 	return Data;
 }
-[\xE0-\xEF][\x80-\xBF]{2} {
+[\xE0-\xEF]([\x80-\xBF]{2}) {
 	ch = (wchar_t)(yytext[0] & 0x0F) << 12
 		| (wchar_t)(yytext[1] & 0x3F) << 6
 		| (wchar_t)(yytext[2] & 0x3F);
 	return Data;
 }
-[\xF0-\xF7][\x80-\xBF]{3} {
+[\xF0-\xF7]([\x80-\xBF]{3}) {
 	ch = (wchar_t)(yytext[0] & 0x07) << 18
 		| (wchar_t)(yytext[1] & 0x3F) << 12
 		| (wchar_t)(yytext[2] & 0x3F) << 6
@@ -554,25 +553,25 @@ int main(int argc, char *argv[]) {
 			break; case 'n': hide = true;
 			break; case 's': size = true;
 			break; case 'w': cols = atoi(optarg);
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 	if (optind < argc) {
 		yyin = fopen(argv[optind], "r");
-		if (!yyin) err(EX_NOINPUT, "%s", argv[optind]);
+		if (!yyin) err(1, "%s", argv[optind]);
 	}
 
 	if (size) {
 		struct winsize win;
 		int error = ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
-		if (error) err(EX_IOERR, "ioctl");
+		if (error) err(1, "ioctl");
 		cols = win.ws_col;
 		rows = win.ws_row;
 	}
 	scr.bot = rows;
 
 	cells = calloc(cols * rows, sizeof(*cells));
-	if (!cells) err(EX_OSERR, "calloc");
+	if (!cells) err(1, "calloc");
 	erase(cell(0, 0), cell(rows-1, cols));
 
 	bool mc = false;
diff --git a/bin/title.c b/bin/title.c
index 82f89d95..f40f5c87 100644
--- a/bin/title.c
+++ b/bin/title.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 #include <wchar.h>
 
@@ -33,7 +32,7 @@ static regex_t regex(const char *pattern, int flags) {
 
 	char buf[256];
 	regerror(error, &regex, buf, sizeof(buf));
-	errx(EX_SOFTWARE, "regcomp: %s: %s", buf, pattern);
+	errx(1, "regcomp: %s: %s", buf, pattern);
 }
 
 static const struct Entity {
@@ -128,7 +127,7 @@ static CURLcode fetchTitle(const char *url) {
 	char *dest;
 	curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &dest);
 	dest = strdup(dest);
-	if (!dest) err(EX_OSERR, "strdup");
+	if (!dest) err(1, "strdup");
 
 	code = curl_easy_setopt(curl, CURLOPT_URL, dest);
 	if (code) return code;
@@ -149,10 +148,10 @@ int main(int argc, char *argv[]) {
 	setlinebuf(stdout);
 
 	CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
-	if (code) errx(EX_OSERR, "curl_global_init: %s", curl_easy_strerror(code));
+	if (code) errx(1, "curl_global_init: %s", curl_easy_strerror(code));
 
 	curl = curl_easy_init();
-	if (!curl) errx(EX_SOFTWARE, "curl_easy_init");
+	if (!curl) errx(1, "curl_easy_init");
 
 	static char error[CURL_ERROR_SIZE];
 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
@@ -180,14 +179,14 @@ int main(int argc, char *argv[]) {
 				excludeRegex = regex(optarg, REG_NOSUB);
 			}
 			break; case 'v': curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
-			break; default:  return EX_USAGE;
+			break; default:  return 1;
 		}
 	}
 
 	if (optind < argc) {
 		code = fetchTitle(argv[optind]);
-		if (!code) return EX_OK;
-		errx(EX_DATAERR, "curl_easy_perform: %s", error);
+		if (!code) return 0;
+		errx(1, "curl_easy_perform: %s", error);
 	}
 
 	char *buf = NULL;
@@ -207,5 +206,5 @@ int main(int argc, char *argv[]) {
 			ptr[match.rm_eo] = ' ';
 		}
 	}
-	if (ferror(stdin)) err(EX_IOERR, "getline");
+	if (ferror(stdin)) err(1, "getline");
 }
diff --git a/bin/up.sh b/bin/up.sh
index cebc29c4..6305b1ee 100644
--- a/bin/up.sh
+++ b/bin/up.sh
@@ -4,21 +4,32 @@ set -eu
 readonly Host='temp.causal.agency'
 readonly Root='/var/www'
 
+temp=
+temp() {
+	temp=$(mktemp -d)
+	trap 'rm -r "$temp"' EXIT
+}
+
+warn=
 upload() {
 	src=$1
 	ext=${src##*.}
-	ts=$(date +'%s')
-	rand=$(openssl rand -hex 4)
-	url=$(printf '%s/%x%s.%s' "$Host" "$ts" "$rand" "$ext")
+	name=$(printf '%x%s' "$(date +%s)" "$(openssl rand -hex 4)")
+	url="${Host}/${name}.${ext}"
 	scp -q "$src" "${Host}:${Root}/${url}"
+	if test -n "$warn"; then
+		test -n "$temp" || temp
+		cat >"${temp}/warn.html" <<-EOF
+			<!DOCTYPE html>
+			<title>${warn}</title>
+			<meta http-equiv="refresh" content="0;url=${name}.${ext}">
+		EOF
+		url="${Host}/${name}.html"
+		scp -q "${temp}/warn.html" "${Host}:${Root}/${url}"
+	fi
 	echo "https://${url}"
 }
 
-temp() {
-	temp=$(mktemp -d)
-	trap 'rm -r "$temp"' EXIT
-}
-
 uploadText() {
 	temp
 	cat >"${temp}/input.txt"
@@ -64,12 +75,13 @@ uploadTerminal() {
 	upload "${temp}/term.html"
 }
 
-while getopts 'chst' opt; do
+while getopts 'chstw:' opt; do
 	case $opt in
 		(c) fn=uploadCommand;;
 		(h) fn=uploadHilex;;
 		(s) fn=uploadScreen;;
 		(t) fn=uploadTerminal;;
+		(w) warn=$OPTARG;;
 		(?) exit 1;;
 	esac
 done
diff --git a/bin/when.y b/bin/when.y
index 64859da7..1d3795ad 100644
--- a/bin/when.y
+++ b/bin/when.y
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  June McEnroe <june@causal.agency>
+/* Copyright (C) 2019, 2022  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -18,10 +18,12 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
-#include <sysexits.h>
 #include <time.h>
 
 static void yyerror(const char *str);
@@ -30,12 +32,13 @@ static int yylex(void);
 #define YYSTYPE struct tm
 
 static const char *Days[7] = {
-	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+	"Sunday", "Monday", "Tuesday", "Wednesday",
+	"Thursday", "Friday", "Saturday",
 };
 
 static const char *Months[12] = {
-	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+	"January", "February", "March", "April", "May", "June",
+	"July", "August", "September", "October", "November", "December",
 };
 
 static const struct tm Week = { .tm_mday = 7 };
@@ -43,14 +46,14 @@ static const struct tm Week = { .tm_mday = 7 };
 static struct tm normalize(struct tm date) {
 	time_t time = timegm(&date);
 	struct tm *norm = gmtime(&time);
-	if (!norm) err(EX_OSERR, "gmtime");
+	if (!norm) err(1, "gmtime");
 	return *norm;
 }
 
 static struct tm today(void) {
 	time_t now = time(NULL);
 	struct tm *local = localtime(&now);
-	if (!local) err(EX_OSERR, "localtime");
+	if (!local) err(1, "localtime");
 	struct tm date = {
 		.tm_year = local->tm_year,
 		.tm_mon = local->tm_mon,
@@ -117,7 +120,10 @@ static struct tm dateDiff(struct tm a, struct tm b) {
 		.tm_mon = a.tm_mon - b.tm_mon,
 		.tm_mday = a.tm_mday - b.tm_mday,
 	};
-	if (a.tm_mon < b.tm_mon) {
+	if (
+		a.tm_mon < b.tm_mon ||
+		(a.tm_mon == b.tm_mon && a.tm_mday < b.tm_mday)
+	) {
 		diff.tm_year--;
 		diff.tm_mon += 12;
 	}
@@ -130,15 +136,50 @@ static struct tm dateDiff(struct tm a, struct tm b) {
 	return diff;
 }
 
+static struct {
+	size_t cap, len;
+	struct tm *ptr;
+} dates;
+
+static struct tm getDate(const char *name) {
+	for (size_t i = 0; i < dates.len; ++i) {
+		if (!strcmp(dates.ptr[i].tm_zone, name)) return dates.ptr[i];
+	}
+	return (struct tm) {0};
+}
+
+static void setDate(const char *name, struct tm date) {
+	for (size_t i = 0; i < dates.len; ++i) {
+		if (strcmp(dates.ptr[i].tm_zone, name)) continue;
+		char *tm_zone = dates.ptr[i].tm_zone;
+		dates.ptr[i] = date;
+		dates.ptr[i].tm_zone = tm_zone;
+		return;
+	}
+	if (dates.len == dates.cap) {
+		dates.cap = (dates.cap ? dates.cap * 2 : 8);
+		dates.ptr = realloc(dates.ptr, sizeof(*dates.ptr) * dates.cap);
+		if (!dates.ptr) err(1, "realloc");
+	}
+	dates.ptr[dates.len] = date;
+	dates.ptr[dates.len].tm_zone = strdup(name);
+	if (!dates.ptr[dates.len].tm_zone) err(1, "strdup");
+	dates.len++;
+}
+
+static bool silent;
+
 static void printDate(struct tm date) {
+	if (silent) return;
 	printf(
-		"%s %s %d %d\n",
+		"%.3s %.3s %d %d\n",
 		Days[date.tm_wday], Months[date.tm_mon],
 		date.tm_mday, 1900 + date.tm_year
 	);
 }
 
 static void printScalar(struct tm scalar) {
+	if (silent) return;
 	if (scalar.tm_year) printf("%dy ", scalar.tm_year);
 	if (scalar.tm_mon) printf("%dm ", scalar.tm_mon);
 	if (scalar.tm_mday % 7) {
@@ -161,7 +202,8 @@ static void printScalar(struct tm scalar) {
 
 %}
 
-%token Number Month Day
+%token Name Number Month Day
+%right '='
 %left '+' '-'
 %right '<' '>'
 
@@ -174,6 +216,8 @@ expr:
 
 date:
 	dateLit
+	| Name { $$ = getDate($1.tm_zone); free($1.tm_zone); }
+	| Name '=' date { setDate($1.tm_zone, $3); free($1.tm_zone); $$ = $3; }
 	| '(' date ')' { $$ = $2; }
 	| '<' date { $$ = dateSub($2, Week); }
 	| '>' date { $$ = dateAdd($2, Week); }
@@ -223,35 +267,77 @@ static int yylex(void) {
 		return Number;
 	}
 
-	for (int i = 0; i < 7; ++i) {
-		if (strncasecmp(input, Days[i], 3)) continue;
-		while (isalpha(*input)) input++;
-		yylval.tm_wday = i;
-		return Day;
+	size_t len;
+	for (len = 0; isalnum(input[len]) || input[len] == '_'; ++len);
+
+	if (len >= 3) {
+		for (int i = 0; i < 7; ++i) {
+			if (strncasecmp(input, Days[i], len)) continue;
+			yylval.tm_wday = i;
+			input += len;
+			return Day;
+		}
+
+		for (int i = 0; i < 12; ++i) {
+			if (strncasecmp(input, Months[i], len)) continue;
+			yylval.tm_mon = i;
+			input += len;
+			return Month;
+		}
 	}
 
-	for (int i = 0; i < 12; ++i) {
-		if (strncasecmp(input, Months[i], 3)) continue;
-		while (isalpha(*input)) input++;
-		yylval.tm_mon = i;
-		return Month;
+	if (len && (len != 1 || !strchr("dwmy", *input))) {
+		yylval.tm_zone = strndup(input, len);
+		if (!yylval.tm_zone) err(1, "strndup");
+		input += len;
+		return Name;
 	}
 
 	return *input++;
 }
 
 int main(int argc, char *argv[]) {
+	size_t cap = 0;
+	char *line = NULL;
+
+	char path[PATH_MAX];
+	const char *configHome = getenv("XDG_CONFIG_HOME");
+	if (configHome) {
+		snprintf(path, sizeof(path), "%s/when/dates", configHome);
+	} else {
+		snprintf(path, sizeof(path), "%s/.config/when/dates", getenv("HOME"));
+	}
+
+	FILE *file = fopen(path, "r");
+	if (file) {
+		silent = true;
+		while (0 < getline(&line, &cap, file)) {
+			input = line;
+			yyparse();
+		}
+		fclose(file);
+		silent = false;
+	} else if (errno != ENOENT) {
+		err(1, "%s", path);
+	}
+
 	if (argc > 1) {
-		input = argv[1];
-		return yyparse();
+		if (strcmp(argv[1], "-")) {
+			input = argv[1];
+			return yyparse();
+		} else {
+			for (size_t i = 0; i < dates.len; ++i) {
+				printf("%s: ", dates.ptr[i].tm_zone);
+				printScalar(dateDiff(today(), dates.ptr[i]));
+			}
+			return 0;
+		}
 	}
 
 	struct tm date = today();
 	printDate(date);
 	printf("\n");
 
-	char *line = NULL;
-	size_t cap = 0;
 	while (0 < getline(&line, &cap, stdin)) {
 		if (line[0] == '\n') continue;
 
diff --git a/bin/xx.c b/bin/xx.c
index 6d04f2f5..89966a38 100644
--- a/bin/xx.c
+++ b/bin/xx.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2017  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -19,7 +19,6 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 typedef unsigned char byte;
@@ -105,7 +104,7 @@ static void undump(FILE *file) {
 	while (0 < (match = fscanf(file, " %hhx", &c))) {
 		printf("%c", c);
 	}
-	if (!match) errx(EX_DATAERR, "invalid input");
+	if (!match) errx(1, "invalid input");
 }
 
 int main(int argc, char *argv[]) {
@@ -122,21 +121,21 @@ int main(int argc, char *argv[]) {
 			break; case 'r': reverse = true;
 			break; case 's': options.offset ^= true;
 			break; case 'z': options.skip ^= true;
-			break; default: return EX_USAGE;
+			break; default: return 1;
 		}
 	}
 	if (argc > optind) path = argv[optind];
-	if (!options.cols) return EX_USAGE;
+	if (!options.cols) return 1;
 
 	FILE *file = path ? fopen(path, "r") : stdin;
-	if (!file) err(EX_NOINPUT, "%s", path);
+	if (!file) err(1, "%s", path);
 
 	if (reverse) {
 		undump(file);
 	} else {
 		dump(file);
 	}
-	if (ferror(file)) err(EX_IOERR, "%s", path);
+	if (ferror(file)) err(1, "%s", path);
 
-	return EX_OK;
+	return 0;
 }
diff --git a/doc/pdf/.gitignore b/doc/pdf/.gitignore
deleted file mode 100644
index a1363379..00000000
--- a/doc/pdf/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.pdf
diff --git a/doc/pdf/Makefile b/doc/pdf/Makefile
deleted file mode 100644
index 7afbdcf2..00000000
--- a/doc/pdf/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-PDFS += abi.pdf
-PDFS += c11.pdf
-PDFS += elf.pdf
-PDFS += intel-64-opt.pdf
-PDFS += intel-64-sdm-vol-1.pdf
-PDFS += intel-64-sdm-vol-2.pdf
-PDFS += intel-64-sdm-vol-3.pdf
-PDFS += intel-64-sdm-vol-4.pdf
-PDFS += multiboot.pdf
-
-ELF = https://refspecs.linuxbase.org/elf
-INTEL = https://software.intel.com/sites/default/files/managed
-
-URL.abi.pdf = ${ELF}/x86_64-abi-0.99.pdf
-URL.c11.pdf = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
-URL.elf.pdf = ${ELF}/elf.pdf
-URL.intel-64-opt.pdf = ${INTEL}/9e/bc/64-ia-32-architectures-optimization-manual.pdf
-URL.intel-64-sdm-vol-1.pdf = ${INTEL}/a4/60/253665-sdm-vol-1.pdf
-URL.intel-64-sdm-vol-2.pdf = ${INTEL}/a4/60/325383-sdm-vol-2abcd.pdf
-URL.intel-64-sdm-vol-3.pdf = ${INTEL}/a4/60/325384-sdm-vol-3abcd.pdf
-URL.intel-64-sdm-vol-4.pdf = ${INTEL}/22/0d/335592-sdm-vol-4.pdf
-URL.multiboot.pdf = https://www.gnu.org/software/grub/manual/multiboot/multiboot.pdf
-
-all: ${PDFS}
-
-${PDFS}:
-	curl -Lf -o $@ ${URL.$@}
-	chmod a-w $@
-
-clean:
-	rm -f ${PDFS}
diff --git a/doc/zlib/adler32.3 b/doc/zlib/adler32.3
index d713d952..c58a34e7 100644
--- a/doc/zlib/adler32.3
+++ b/doc/zlib/adler32.3
@@ -58,7 +58,7 @@ if (adler != original_adler) error();
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/adler32_combine.3 b/doc/zlib/adler32_combine.3
index 861f235b..55e801e9 100644
--- a/doc/zlib/adler32_combine.3
+++ b/doc/zlib/adler32_combine.3
@@ -56,7 +56,7 @@ the result has no meaning or utility.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/compress.3 b/doc/zlib/compress.3
index 22b229ee..16445e2f 100644
--- a/doc/zlib/compress.3
+++ b/doc/zlib/compress.3
@@ -77,7 +77,7 @@ parameter is invalid.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/compressBound.3 b/doc/zlib/compressBound.3
index 5800e2ba..d61891eb 100644
--- a/doc/zlib/compressBound.3
+++ b/doc/zlib/compressBound.3
@@ -37,7 +37,7 @@ call to allocate the destination buffer.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/crc32.3 b/doc/zlib/crc32.3
index 3c9cc8c4..a42df2af 100644
--- a/doc/zlib/crc32.3
+++ b/doc/zlib/crc32.3
@@ -59,7 +59,7 @@ if (crc != original_crc) error();
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/crc32_combine.3 b/doc/zlib/crc32_combine.3
index 2f79f623..b25da679 100644
--- a/doc/zlib/crc32_combine.3
+++ b/doc/zlib/crc32_combine.3
@@ -47,7 +47,7 @@ and
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflate.3 b/doc/zlib/deflate.3
index 7df313ee..be182d96 100644
--- a/doc/zlib/deflate.3
+++ b/doc/zlib/deflate.3
@@ -363,7 +363,7 @@ to continue compressing.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateBound.3 b/doc/zlib/deflateBound.3
index 63e80246..be97494c 100644
--- a/doc/zlib/deflateBound.3
+++ b/doc/zlib/deflateBound.3
@@ -64,7 +64,7 @@ are used.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateCopy.3 b/doc/zlib/deflateCopy.3
index f30d6301..f20e0a9e 100644
--- a/doc/zlib/deflateCopy.3
+++ b/doc/zlib/deflateCopy.3
@@ -59,7 +59,7 @@ in both source and destination.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateEnd.3 b/doc/zlib/deflateEnd.3
index e24259a3..0abaabe1 100644
--- a/doc/zlib/deflateEnd.3
+++ b/doc/zlib/deflateEnd.3
@@ -43,7 +43,7 @@ may be set but then points to a static string
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateGetDictionary.3 b/doc/zlib/deflateGetDictionary.3
index 403f6d10..b9dabfe2 100644
--- a/doc/zlib/deflateGetDictionary.3
+++ b/doc/zlib/deflateGetDictionary.3
@@ -72,7 +72,7 @@ if the stream state is inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateInit.3 b/doc/zlib/deflateInit.3
index a893dd91..52179883 100644
--- a/doc/zlib/deflateInit.3
+++ b/doc/zlib/deflateInit.3
@@ -171,7 +171,7 @@ if there is no error message.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateInit2.3 b/doc/zlib/deflateInit2.3
index 6a581ef8..a7d68b99 100644
--- a/doc/zlib/deflateInit2.3
+++ b/doc/zlib/deflateInit2.3
@@ -220,7 +220,7 @@ is set to null if there is no error message.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateParams.3 b/doc/zlib/deflateParams.3
index 8e770d4e..9eb5ca16 100644
--- a/doc/zlib/deflateParams.3
+++ b/doc/zlib/deflateParams.3
@@ -116,7 +116,7 @@ with more output space.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflatePending.3 b/doc/zlib/deflatePending.3
index 1ce40fc2..35fa6d38 100644
--- a/doc/zlib/deflatePending.3
+++ b/doc/zlib/deflatePending.3
@@ -49,7 +49,7 @@ if the source stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflatePrime.3 b/doc/zlib/deflatePrime.3
index 639e715a..10a2924b 100644
--- a/doc/zlib/deflatePrime.3
+++ b/doc/zlib/deflatePrime.3
@@ -57,7 +57,7 @@ if the source stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateReset.3 b/doc/zlib/deflateReset.3
index 7309ac15..1a18c507 100644
--- a/doc/zlib/deflateReset.3
+++ b/doc/zlib/deflateReset.3
@@ -50,7 +50,7 @@ being
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateSetDictionary.3 b/doc/zlib/deflateSetDictionary.3
index c2c9d7c2..3e66d3cf 100644
--- a/doc/zlib/deflateSetDictionary.3
+++ b/doc/zlib/deflateSetDictionary.3
@@ -135,7 +135,7 @@ for raw deflate
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateSetHeader.3 b/doc/zlib/deflateSetHeader.3
index 6fec645c..03d4f4d3 100644
--- a/doc/zlib/deflateSetHeader.3
+++ b/doc/zlib/deflateSetHeader.3
@@ -173,7 +173,7 @@ if the source stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/deflateTune.3 b/doc/zlib/deflateTune.3
index 7269dec0..ea4dd915 100644
--- a/doc/zlib/deflateTune.3
+++ b/doc/zlib/deflateTune.3
@@ -63,7 +63,7 @@ for an invalid deflate stream.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzbuffer.3 b/doc/zlib/gzbuffer.3
index de7c706a..92438c48 100644
--- a/doc/zlib/gzbuffer.3
+++ b/doc/zlib/gzbuffer.3
@@ -52,7 +52,7 @@ such as being called too late.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzclose.3 b/doc/zlib/gzclose.3
index 77eae11e..bfcc583e 100644
--- a/doc/zlib/gzclose.3
+++ b/doc/zlib/gzclose.3
@@ -90,7 +90,7 @@ on success.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzdirect.3 b/doc/zlib/gzdirect.3
index 8fa26aae..640fd4c5 100644
--- a/doc/zlib/gzdirect.3
+++ b/doc/zlib/gzdirect.3
@@ -78,7 +78,7 @@ which may not be desired.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzeof.3 b/doc/zlib/gzeof.3
index 26c415fe..ba823aa6 100644
--- a/doc/zlib/gzeof.3
+++ b/doc/zlib/gzeof.3
@@ -56,7 +56,7 @@ end of file was detected.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzerror.3 b/doc/zlib/gzerror.3
index 13dcddd4..a9e175fc 100644
--- a/doc/zlib/gzerror.3
+++ b/doc/zlib/gzerror.3
@@ -68,7 +68,7 @@ that is being written concurrently.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzflush.3 b/doc/zlib/gzflush.3
index b93c03e7..476f7c09 100644
--- a/doc/zlib/gzflush.3
+++ b/doc/zlib/gzflush.3
@@ -66,7 +66,7 @@ see function
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzfread.3 b/doc/zlib/gzfread.3
index 66231cc3..7bf57fc5 100644
--- a/doc/zlib/gzfread.3
+++ b/doc/zlib/gzfread.3
@@ -100,7 +100,7 @@ and the error state is set to
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzfwrite.3 b/doc/zlib/gzfwrite.3
index 38383a33..6835db3a 100644
--- a/doc/zlib/gzfwrite.3
+++ b/doc/zlib/gzfwrite.3
@@ -68,7 +68,7 @@ and the error state is set to
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzgetc.3 b/doc/zlib/gzgetc.3
index 93a90edd..db9143ec 100644
--- a/doc/zlib/gzgetc.3
+++ b/doc/zlib/gzgetc.3
@@ -48,7 +48,7 @@ or error.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzgets.3 b/doc/zlib/gzgets.3
index 2a329e9e..c1435b39 100644
--- a/doc/zlib/gzgets.3
+++ b/doc/zlib/gzgets.3
@@ -60,7 +60,7 @@ are indeterminate.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzoffset.3 b/doc/zlib/gzoffset.3
index cbb78a77..b03c557e 100644
--- a/doc/zlib/gzoffset.3
+++ b/doc/zlib/gzoffset.3
@@ -44,7 +44,7 @@ returns -1.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzopen.3 b/doc/zlib/gzopen.3
index e3cb4cbd..9da647e1 100644
--- a/doc/zlib/gzopen.3
+++ b/doc/zlib/gzopen.3
@@ -254,7 +254,7 @@ for the routine
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzprintf.3 b/doc/zlib/gzprintf.3
index 26961f34..a2a241a2 100644
--- a/doc/zlib/gzprintf.3
+++ b/doc/zlib/gzprintf.3
@@ -64,7 +64,7 @@ This can be determined using
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzputc.3 b/doc/zlib/gzputc.3
index 161e5631..66897b5e 100644
--- a/doc/zlib/gzputc.3
+++ b/doc/zlib/gzputc.3
@@ -36,7 +36,7 @@ or -1 in case of error.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzputs.3 b/doc/zlib/gzputs.3
index f5d1fd84..71833ab2 100644
--- a/doc/zlib/gzputs.3
+++ b/doc/zlib/gzputs.3
@@ -34,7 +34,7 @@ or -1 in case of error.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzread.3 b/doc/zlib/gzread.3
index 84439eaa..4118eca7 100644
--- a/doc/zlib/gzread.3
+++ b/doc/zlib/gzread.3
@@ -108,7 +108,7 @@ and the error state is set to
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzseek.3 b/doc/zlib/gzseek.3
index cd85fd4c..a14b2db6 100644
--- a/doc/zlib/gzseek.3
+++ b/doc/zlib/gzseek.3
@@ -101,7 +101,7 @@ would be before the current position.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzsetparams.3 b/doc/zlib/gzsetparams.3
index ff544d23..f6ff9ed7 100644
--- a/doc/zlib/gzsetparams.3
+++ b/doc/zlib/gzsetparams.3
@@ -44,7 +44,7 @@ if there is a memory allocation error.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzungetc.3 b/doc/zlib/gzungetc.3
index 90cdafc7..fbe9371c 100644
--- a/doc/zlib/gzungetc.3
+++ b/doc/zlib/gzungetc.3
@@ -60,7 +60,7 @@ or -1 on failure.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/gzwrite.3 b/doc/zlib/gzwrite.3
index 606d89f4..73407ef5 100644
--- a/doc/zlib/gzwrite.3
+++ b/doc/zlib/gzwrite.3
@@ -32,7 +32,7 @@ or 0 in case of error.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflate.3 b/doc/zlib/inflate.3
index ca90c270..255e0f84 100644
--- a/doc/zlib/inflate.3
+++ b/doc/zlib/inflate.3
@@ -391,7 +391,7 @@ is to be attempted.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateBack.3 b/doc/zlib/inflateBack.3
index 59d5f8cb..fcda7452 100644
--- a/doc/zlib/inflateBack.3
+++ b/doc/zlib/inflateBack.3
@@ -278,7 +278,7 @@ cannot return
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateBackEnd.3 b/doc/zlib/inflateBackEnd.3
index eeb88636..39fbea8f 100644
--- a/doc/zlib/inflateBackEnd.3
+++ b/doc/zlib/inflateBackEnd.3
@@ -36,7 +36,7 @@ if the stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateBackInit.3 b/doc/zlib/inflateBackInit.3
index 483edda5..d029542e 100644
--- a/doc/zlib/inflateBackInit.3
+++ b/doc/zlib/inflateBackInit.3
@@ -77,7 +77,7 @@ does not match the version of the header file.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateCopy.3 b/doc/zlib/inflateCopy.3
index 53b30edf..167b879b 100644
--- a/doc/zlib/inflateCopy.3
+++ b/doc/zlib/inflateCopy.3
@@ -52,7 +52,7 @@ in both source and destination.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateEnd.3 b/doc/zlib/inflateEnd.3
index 9b18226b..54945b50 100644
--- a/doc/zlib/inflateEnd.3
+++ b/doc/zlib/inflateEnd.3
@@ -37,7 +37,7 @@ if the stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateGetDictionary.3 b/doc/zlib/inflateGetDictionary.3
index e70ee736..9290850c 100644
--- a/doc/zlib/inflateGetDictionary.3
+++ b/doc/zlib/inflateGetDictionary.3
@@ -62,7 +62,7 @@ if the stream state is inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateGetHeader.3 b/doc/zlib/inflateGetHeader.3
index f77670f2..57f7c443 100644
--- a/doc/zlib/inflateGetHeader.3
+++ b/doc/zlib/inflateGetHeader.3
@@ -163,7 +163,7 @@ if the source stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateInit.3 b/doc/zlib/inflateInit.3
index 186b058a..66a1d4f7 100644
--- a/doc/zlib/inflateInit.3
+++ b/doc/zlib/inflateInit.3
@@ -94,7 +94,7 @@ is set to null if there is no error message.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateInit2.3 b/doc/zlib/inflateInit2.3
index a630f12a..5b8b49ac 100644
--- a/doc/zlib/inflateInit2.3
+++ b/doc/zlib/inflateInit2.3
@@ -174,7 +174,7 @@ is set to null if there is no error message.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateMark.3 b/doc/zlib/inflateMark.3
index 2d15993d..90e2ee0b 100644
--- a/doc/zlib/inflateMark.3
+++ b/doc/zlib/inflateMark.3
@@ -81,7 +81,7 @@ or -65536 if the provided source stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflatePrime.3 b/doc/zlib/inflatePrime.3
index c89dc2c5..66953665 100644
--- a/doc/zlib/inflatePrime.3
+++ b/doc/zlib/inflatePrime.3
@@ -66,7 +66,7 @@ if the source stream state was inconsistent.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateReset.3 b/doc/zlib/inflateReset.3
index a8d2e219..53c4ffe2 100644
--- a/doc/zlib/inflateReset.3
+++ b/doc/zlib/inflateReset.3
@@ -74,7 +74,7 @@ parameter is invalid.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateSetDictionary.3 b/doc/zlib/inflateSetDictionary.3
index 0e3c60c7..291c97e8 100644
--- a/doc/zlib/inflateSetDictionary.3
+++ b/doc/zlib/inflateSetDictionary.3
@@ -78,7 +78,7 @@ doesn't match the expected one
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/inflateSync.3 b/doc/zlib/inflateSync.3
index 35264ddd..56d3ca28 100644
--- a/doc/zlib/inflateSync.3
+++ b/doc/zlib/inflateSync.3
@@ -65,7 +65,7 @@ until success or the end of the input data.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/uncompress.3 b/doc/zlib/uncompress.3
index d951da9b..1047ad91 100644
--- a/doc/zlib/uncompress.3
+++ b/doc/zlib/uncompress.3
@@ -85,7 +85,7 @@ with the uncompressed data up to that point.
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/zlibCompileFlags.3 b/doc/zlib/zlibCompileFlags.3
index 465195c2..59cc24a8 100644
--- a/doc/zlib/zlibCompileFlags.3
+++ b/doc/zlib/zlibCompileFlags.3
@@ -156,7 +156,7 @@ not secure!
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/doc/zlib/zlibVersion.3 b/doc/zlib/zlibVersion.3
index 35a9854b..04377527 100644
--- a/doc/zlib/zlibVersion.3
+++ b/doc/zlib/zlibVersion.3
@@ -38,7 +38,7 @@ and
 This manual page was converted from
 .In zlib.h
 to mdoc format by
-.An C. McEnroe Aq Mt june@causal.agency .
+.An June McEnroe Aq Mt june@causal.agency .
 .
 .Sh AUTHORS
 .An Jean-loup Gailly Aq Mt jloup@gzip.org
diff --git a/gpl.c b/gpl.c
index 8634449b..8ff4916d 100644
--- a/gpl.c
+++ b/gpl.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2022  June McEnroe <june@causal.agency>
+/* Copyright (C) 2024  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,4 +17,3 @@
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
diff --git a/home/.config/X/resources b/home/.config/X/resources
index cfedf60b..f4603cd9 100644
--- a/home/.config/X/resources
+++ b/home/.config/X/resources
@@ -26,7 +26,7 @@ XTerm*VT100*translations: #override \n\
 	<Btn4Down>: scroll-back(1,line,m) \n\
 	<Btn5Down>: scroll-forw(1,line,m)
 
-XTerm*faceName: Go Mono:size=11
+XTerm*faceName: Go Mono:size=12
 XTerm*internalBorder: 6
 XTerm*colorBDMode: true
 XTerm*scrollBar: false
diff --git a/home/.config/git/config b/home/.config/git/config
index 1a6d5ce1..c990de2c 100644
--- a/home/.config/git/config
+++ b/home/.config/git/config
@@ -2,6 +2,9 @@
 	name = June McEnroe
 	email = june@causal.agency
 
+[branch]
+	sort = committerdate
+
 [commit]
 	verbose = true
 
@@ -12,6 +15,9 @@
 [merge]
 	conflictStyle = diff3
 
+[push]
+	autoSetupRemote = true
+
 [pull]
 	rebase = true
 
@@ -21,5 +27,8 @@
 [pretty]
 	log = %Cred%h %Creset%s%C(yellow)%d %Cgreen(%ar) %Cblue<%aN>
 
+[alias]
+	forgive = blame
+
 [include]
 	path = ./private
diff --git a/home/.local/bin/mins b/home/.local/bin/mins
new file mode 100755
index 00000000..9cbd5fa8
--- /dev/null
+++ b/home/.local/bin/mins
@@ -0,0 +1,4 @@
+#!/bin/sh
+exec dc <<EOF
+$1 60~rn[h]nn[m]p
+EOF
diff --git a/home/.shrc b/home/.shrc
index 1d7542a3..afa87fe5 100644
--- a/home/.shrc
+++ b/home/.shrc
@@ -25,7 +25,7 @@ man() {
 	for sect in $MANSECT; do
 		command man -w $sect "$1" >/dev/null 2>&1 && exec man $sect "$1"
 	done
-	exec man "$1")
+	exec command man "$1")
 }
 
 cd() {
@@ -50,15 +50,5 @@ fi
 export LESS_TERMCAP_us=$(tput sitm)
 export LESS_TERMCAP_ue=$(tput ritm)
 
-hostname=$(hostname -s)
-rprompt() {
-	local pwd
-	pwd=${PWD#${HOME}}
-	[ "${pwd}" != "${PWD}" ] && pwd="~${pwd}"
-	[ "${TERM%-*}" = 'xterm' ] \
-		&& printf '\33]0;%s\a' "${SSH_CLIENT:+${hostname}:}${pwd##*/}" >&2
-	printf '%s' "${SSH_CLIENT:+${hostname}:}${pwd}"
-}
-PS1='
-$ '
-RPS1='${?#0} $(rprompt)'
+PS1='\[\033]0;${SSH_CLIENT:+\\h:}\W\a\]
+${?#0}$ '
diff --git a/home/.ssh/config b/home/.ssh/config
index d354a6ea..f579ae9f 100644
--- a/home/.ssh/config
+++ b/home/.ssh/config
@@ -1,20 +1,17 @@
 IgnoreUnknown Include
 Include config_private
 
+AddKeysToAgent yes
 SendEnv LANG LC_*
 
-Host monday beastie puffy toaster tux progynova
+Host tuesday beastie puffy toaster tux progynova
 	HostName %h.local
 	ForwardAgent yes
 	RemoteForward 7062 127.0.0.1:7062
 
-Host scout pyro
+Host scout soldier pyro demo heavy engi medic sniper spy
 	HostName %h.causal.agency
 	Port 2222
 
-Host june july
-	HostName %h.nyc3.do.causal.agency
-	Port 2222
-
 Host git.causal.agency temp.causal.agency
 	Port 2222
diff --git a/home/.xsession b/home/.xsession
index a51d52f2..1e05126c 100644
--- a/home/.xsession
+++ b/home/.xsession
@@ -4,8 +4,11 @@ export LC_CTYPE=en_US.UTF-8
 xset r rate 175 m 5/4 0
 xmodmap ~/.config/X/modmap
 xrdb -load ~/.config/X/resources
-xsetroot -bitmap /usr/X11R6/include/X11/bitmaps/xsnow \
-	-bg rgb:14/13/0E -fg rgb:7A/49/55 
+
+fg=998D6B
+command -v scheme && fg=$(scheme -p $(jot -r 1 1 8))
+xsetroot -bitmap /usr/X11R6/include/X11/bitmaps/escherknot \
+	-bg '#14130E' -fg "#${fg}"
 
 xterm -name clock -geometry 14x1-0+0 -sl 0 -e clock &
 exec cwm -c ~/.config/cwm/cwmrc
diff --git a/install.sh b/install.sh
index 1d9b6e6b..11269fb7 100644
--- a/install.sh
+++ b/install.sh
@@ -33,7 +33,7 @@ Darwin() {
 	packages=$(echo $packages | sed 's/the_silver_searcher/ag/')
 	cd git/jorts
 	git pull
-	./Plan git mandoc nvi $packages | sh
+	./Install git mandoc nvi $packages
 }
 
 $(uname)
diff --git a/txt/books.txt b/txt/books.txt
index 88af73b0..ec739490 100644
--- a/txt/books.txt
+++ b/txt/books.txt
@@ -1,5 +1,35 @@
+[ 2025 ]
+
+  2. ★★☆ Nicola Griffith, Spear
+  1. ★★☆ Ruthanna Emrys, A Half-Built Garden
+
+[ 2024 ]
+
+  2. ★☆☆ R. A. MacAvoy, Tea with the Black Dragon
+  1. ★☆☆ Sybil Lamb, The Girl Who Was Convinced Beyond All Reason That She Could Fly
+
+[ 2023 ]
+
+  7. ★★☆ Alix E. Harrow, Starling House
+  6. ★★☆ Alix E. Harrow, A Mirror Mended
+  5. ★★★ Alix E. Harrow, A Spindle Splintered
+  4. ★★☆ Alyson Greaves, The Sisters of Dorley (ch. 1-15)
+  3. ★☆☆ Nnedi Okorafor, Noor
+  2. ★★☆ Nnedi Okorafor, Remote Control
+  1. ★★☆ Becky Chambers, A Prayer for the Crown-Shy
+
 [ 2022 ]
 
+ 15. ★★★ Becky Chambers, The Long Way To a Small Angry Planet
+ 14. ★★★ ed. Tristan Taormino, Take Me There
+ 13. ★★★★ Becky Chambers, A Closed and Common Orbit
+ 12. ★★☆ Sybil Lamb, I've Got a Time Bomb
+ 11. ☆☆☆ Ruth Ozeki, The Book of Form and Emptiness
+ 10. ★☆☆ Sally Rooney, Conversations With Friends
+  9. ★☆☆ Sally Rooney, Normal People
+  8. ★★★ Andrea Stewart, The Bone Shard Emperor
+  7. ★★☆ ed. Gwen Benaway, Maiden, Mother, Crone
+  6. ★★★ Andrea Stewart, The Bone Shard Daughter
   5. ★☆☆ Madeline Miller, Circe
   4. ★★★ Natalie Zina Walschots, Hench
   3. ★★★ V. E. Schwab, The Invisible Life of Addie LaRue
diff --git a/txt/shows.txt b/txt/shows.txt
index 62e6a071..a9c5ee95 100644
--- a/txt/shows.txt
+++ b/txt/shows.txt
@@ -1,3 +1,6 @@
+2024-06-21 (La Sala Rossa) MAGELLA, Quinton Barnes, BACKXWASH
+2022-12-18 (SAT) LINGUA IGNOTA
+2022-06-04 (MAI) Honeydrip, MAGELLA, BACKXWASH
 2020-01-23 (La Sala Rossa) Secondsight, BIG|BRAVE
 2019-12-10 (Casa del Popolo) meth, Street Sects
 2019-06-22 (Casa del Popolo) Persons Unknown, Palissade, Police des Moeurs, Blu Anxiety
diff --git a/txt/tweets.txt b/txt/tweets.txt
deleted file mode 100644
index 240351ec..00000000
--- a/txt/tweets.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-triangle forum
-https://twitter.com/g0m/status/963890156477603841
-
-damn ya ass fat what's ya pronouns?
-https://twitter.com/msbigmilk/status/1291218055939448833
-
-afab
-https://twitter.com/ErisGael/status/1257524779046907904
-
-chaos emeralds
-https://twitter.com/ErisGael/status/1190147736244490240
-
-might as well salivate
-https://twitter.com/prawn_meat/status/857444039833944064
-
-notifications
-https://twitter.com/WTMMP/status/1259694226595610629
-
-all robot & computers
-https://twitter.com/cryptcrier/status/1238339418160680960
-
-the wet world
-https://twitter.com/TragicAllyHere/status/1137187876507140098
-
-a purchase?
-https://twitter.com/pant_leg/status/1027693563604230144
-
-influencer
-https://twitter.com/witchpuppy/status/974690828257054721
-
--Wint-conversion
-https://twitter.com/jckarter/status/967802665080995840
diff --git a/www/causal.agency/.gitignore b/www/causal.agency/.gitignore
index 7935a3c1..b00b1c3c 100644
--- a/www/causal.agency/.gitignore
+++ b/www/causal.agency/.gitignore
@@ -1,3 +1,4 @@
-*.html
+index.html
+leveler.html
 scheme.css
 scheme.png
diff --git a/www/causal.agency/Makefile b/www/causal.agency/Makefile
index 75849db0..8c74f8f1 100644
--- a/www/causal.agency/Makefile
+++ b/www/causal.agency/Makefile
@@ -1,11 +1,14 @@
 WEBROOT = /var/www/causal.agency
 
-FILES = index.html style.css scheme.css scheme.png
+GEN = index.html scheme.css scheme.png
+FILES = ${GEN} style.css alpha.html lands.html
 
 all: ${FILES}
 
-index.html: index.7
-	mandoc -T html -O style=style.css index.7 > index.html
+.SUFFIXES: .7 .html
+
+.7.html:
+	mandoc -T html -O style=style.css $< > $@
 
 scheme.css:
 	scheme -st > scheme.css
@@ -17,4 +20,4 @@ install: ${FILES}
 	install -C -m 644 ${FILES} ${WEBROOT}
 
 clean:
-	rm -f index.html scheme.css scheme.png
+	rm -f ${GEN}
diff --git a/www/causal.agency/alpha.html b/www/causal.agency/alpha.html
new file mode 100644
index 00000000..0d83f530
--- /dev/null
+++ b/www/causal.agency/alpha.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>all 26 letters of the alphabet RANKED</title>
+<style>
+body, button { font-size: 200%; text-align: center; }
+button { margin: 1em; padding: 1ch; }
+button#shuffle { font-size: 100%; }
+</style>
+
+which letter do you like more?
+<p>
+<button id="a">A</button>
+<button id="b">B</button>
+<p>
+<details>
+<summary>current ranking</summary>
+<p>
+<span id="ranking">ABCDEFGHIJKLMNOPQRSTUVWXYZ</span>
+<p>
+<button id="shuffle">reshuffle</button>
+</details>
+
+<script>
+let buttonA = document.getElementById("a");
+let buttonB = document.getElementById("b");
+let ranking = document.getElementById("ranking");
+
+let alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
+let rand = (bound) => Math.floor(Math.random() * bound);
+function shuffle() {
+	for (let i = alpha.length - 1; i > 0; --i) {
+		let j = rand(i + 1);
+		let x = alpha[i];
+		alpha[i] = alpha[j];
+		alpha[j] = x;
+	}
+}
+if (localStorage.getItem("alpha")) {
+	alpha = localStorage.getItem("alpha").split("");
+} else {
+	shuffle();
+}
+
+let index = 0;
+let even = true;
+function choose(o) {
+	if (o == "b") {
+		let x = alpha[index];
+		alpha[index] = alpha[index + 1];
+		alpha[index + 1] = x;
+	}
+	index += 2;
+	if (index > alpha.length - 2) {
+		even = !even;
+		index = (even ? 0 : 1);
+	}
+	update();
+}
+
+document.onkeydown = function(event) {
+	if (event.key.toUpperCase() == alpha[index]) {
+		choose("a");
+	} else if (event.key.toUpperCase() == alpha[index + 1]) {
+		choose("b");
+	}
+}
+
+function update() {
+	localStorage.setItem("alpha", alpha.join(""));
+	ranking.innerText = alpha.join("");
+	let a = buttonA;
+	let b = buttonB;
+	if (rand(2)) {
+		a = buttonB;
+		b = buttonA;
+	}
+	let lc = (c) => c;
+	if (rand(2)) lc = (c) => c.toLowerCase();
+	a.innerText = lc(alpha[index]);
+	b.innerText = lc(alpha[index + 1]);
+	a.onclick = () => choose("a");
+	b.onclick = () => choose("b");
+}
+update();
+
+document.getElementById("shuffle").onclick = function() {
+	if (confirm("Are you SURE you want to throw away all your hard work?")) {
+		shuffle();
+		update();
+	}
+}
+</script>
diff --git a/www/causal.agency/index.7 b/www/causal.agency/index.7
index c270f477..75c37d87 100644
--- a/www/causal.agency/index.7
+++ b/www/causal.agency/index.7
@@ -1,10 +1,10 @@
-.Dd November  3, 2021
+.Dd June 16, 2024
 .Dt CAUSAL.AGENCY 7
 .Os "Causal Agency"
 .
 .Sh NAME
 .Nm june
-.Nd computer enthusiast (her)
+.Nd enthusiast (she/they)
 .
 .Sh SYNOPSIS
 .Nm mail
@@ -15,20 +15,21 @@ in
 on tilde.chat
 .
 .Sh DESCRIPTION
-I make mostly IRC software in C.
+I like photography,
+Magic: The Gathering
+and making mostly IRC software in C.
 I like
 .Ox
 but also the GPL.
-I just want to read books
-and try to learn to be kinder.
-When I can I'd like to talk to strangers
-and experience more magic.
+I'm learning how to be a person.
 .
 .Pp
 .Lk https://git.causal.agency code
 \(em
 .Lk https://text.causal.agency words
 \(em
+.Lk https://photo.causal.agency photos
+\(em
 .Lk /list/ mailist
 .
 .Pp
@@ -42,7 +43,7 @@ a cosy IRC client
 a full-text search IRC logger
 .It Lk https://git.causal.agency/scooper/about scooper
 a web interface for litterbox
-.It Lk https://git.causal.agency/catsit/about catsit
+.It Lk https://git.causal.agency/kitd/about kitd
 a process supervisor
 .It Lk https://git.causal.agency/imbox/about "imbox & git-fetch-email"
 a tool to pull patches out of IMAP
@@ -64,4 +65,11 @@ an earthy terminal colour scheme
 .El
 .
 .Sh SEE ALSO
+.Bl -bullet
+.It
 .Lk /bin/ bin
+.It
+.Lk lands.html "Magic lands quiz"
+.It
+.Lk alpha.html "alphabet ranking game"
+.El
diff --git a/www/causal.agency/lands.html b/www/causal.agency/lands.html
new file mode 100644
index 00000000..7aaadd80
--- /dev/null
+++ b/www/causal.agency/lands.html
@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+<title>Lands Quiz</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<style>
+html { font: 14pt sans-serif; line-height: 1.5em; }
+body { padding: 1em 1ch; max-width: 78ch; margin: auto; }
+h1 { text-align: center; }
+h2 { margin-top: 0; }
+button { font-size: 100%; padding: 0.5em 1ch; }
+img { max-width: 100%; }
+div.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 2ch; }
+</style>
+
+<h1 id="loading">Loading...</h1>
+<h1 id="error" hidden>Failed to load cards :(</h1>
+
+<div id="game" hidden>
+<h1>Magic Lands Quiz</h1>
+<p>Try to guess the colours of mana each land produces!</p>
+<div class="cols">
+	<div>
+		<img id="back" src="https://backs.scryfall.io/normal/0/a/0aeebaf5-8c7d-4636-9e82-8c27447861f7.jpg">
+		<a id="link" target="_blank">
+			<img id="image1" hidden>
+			<img id="image2" hidden>
+		</a>
+	</div>
+	<div>
+		<h2 id="name"></h2>
+		<input type="checkbox" id="w"> <label for="w">White</label><br>
+		<input type="checkbox" id="u"> <label for="u">Blue</label><br>
+		<input type="checkbox" id="b"> <label for="b">Black</label><br>
+		<input type="checkbox" id="r"> <label for="r">Red</label><br>
+		<input type="checkbox" id="g"> <label for="g">Green</label><br>
+		<p><button id="submit">Submit</button></p>
+		<h3>Score: <span id="score">0</span>/<span id="total">0</span></h3>
+	</div>
+</div>
+</div>
+
+<script>
+function shuffle(arr) {
+	let rand = (bound) => Math.floor(Math.random() * bound);
+	for (let i = arr.length-1; i > 0; --i) {
+		let j = rand(i+1);
+		let x = arr[i];
+		arr[i] = arr[j];
+		arr[j] = x;
+	}
+}
+
+const CardBack =
+"https://backs.scryfall.io/normal/0/a/0aeebaf5-8c7d-4636-9e82-8c27447861f7.jpg";
+
+function hideCard() {
+	document.getElementById("back").hidden = false;
+	document.getElementById("image1").hidden = true;
+	document.getElementById("image2").hidden = true;
+}
+
+function showCard(card) {
+	document.getElementById("back").hidden = true;
+	document.getElementById("link").href = card.scryfall_uri;
+	let image1 = document.getElementById("image1");
+	let image2 = document.getElementById("image2");
+	if (card.card_faces) {
+		image1.src = card.card_faces[0].image_uris.normal;
+		image2.src = card.card_faces[1].image_uris.normal;
+		image1.hidden = false;
+		image2.hidden = false;
+	} else {
+		image1.src = card.image_uris.normal;
+		image1.hidden = false;
+	}
+}
+
+function resetChecks() {
+	for (let c of "wubrg") {
+		let input = document.getElementById(c);
+		input.checked = false;
+		input.disabled = false;
+		input.labels[0].style.fontWeight = "normal";
+	}
+}
+
+function checkChecks(card) {
+	let score = 0;
+	let total = 0;
+	let checked = 0;
+	for (let c of "wubrg") {
+		let input = document.getElementById(c);
+		let produced = card.produced_mana.includes(c.toUpperCase());
+		if (produced) {
+			total++;
+			input.labels[0].style.fontWeight = "bold";
+			if (input.checked) score++;
+		}
+		if (input.checked) checked++;
+		input.disabled = true;
+	}
+	if (checked > total) score -= (checked - total);
+	if (score < 0) score = 0;
+	return { score: score, total: total };
+}
+
+document.onkeydown = function(event) {
+	for (let c of "wubrg") {
+		if (event.key == c) {
+			let input = document.getElementById(c);
+			if (!input.disabled) input.checked ^= true;
+		}
+	}
+	if (event.key == "Enter") {
+		document.getElementById("submit").click();
+	}
+}
+
+let score = 0;
+let total = 0;
+let cards = [];
+let card = null;
+
+function nextCard() {
+	hideCard();
+	resetChecks();
+	card = cards.shift();
+	document.getElementById("name").innerText = card.name;
+}
+
+document.getElementById("submit").onclick = function() {
+	if (card) {
+		let { score: cardScore, total: cardTotal } = checkChecks(card);
+		total += cardTotal;
+		score += cardScore;
+		document.getElementById("score").innerText = score;
+		document.getElementById("total").innerText = total;
+		showCard(card);
+		card = null;
+		if (cards.length) {
+			this.innerText = "Next card";
+		} else {
+			this.disabled = true;
+			this.innerText = "No more cards";
+		}
+	} else {
+		nextCard();
+		this.innerText = "Submit";
+	}
+}
+
+function loadCards(resp) {
+	let loading = document.getElementById("loading");
+	let error = document.getElementById("error");
+	let game = document.getElementById("game");
+	if (resp.status != 200) {
+		loading.hidden = true;
+		error.hidden = false;
+	}
+	resp.json().then((json) => {
+		cards.push(...json.data);
+		if (json.has_more) {
+			setTimeout(() => fetch(json.next_page).then(loadCards), 50);
+		} else {
+			loading.hidden = true;
+			game.hidden = false;
+			shuffle(cards);
+			nextCard();
+		}
+	});
+}
+
+const Search =
+"https://api.scryfall.com/cards/search?q=t:land+id>=2+produces>=2+produces!=wubrg";
+fetch(Search).then(loadCards);
+
+</script>
diff --git a/www/causal.agency/style.css b/www/causal.agency/style.css
index 368d8da1..265c62c2 100644
--- a/www/causal.agency/style.css
+++ b/www/causal.agency/style.css
@@ -11,6 +11,11 @@ dl.Bl-diag > dt { font-weight: bold; }
 code.Nm, code.Fl, code.Cm, code.Ic, code.In, code.Fd, code.Fn,
 code.Cd { font-weight: bold; font-family: inherit; }
 
+div.head, div.foot { display: flex; justify-content: space-between; }
+.head-ltitle, .foot-date { flex: 1; }
+.head-vol { flex: 0 1 auto; text-align: center; }
+.head-rtitle, .foot-os { flex: 1; text-align: right; }
+
 html { font-family: monospace; line-height: 1.25em; }
 body { max-width: 80ch; margin: 1em auto; padding: 0 1ch; }
 table { border-collapse: collapse; }
diff --git a/www/git.causal.agency/.gitignore b/www/git.causal.agency/.gitignore
index 25e26cc8..eaed8039 100644
--- a/www/git.causal.agency/.gitignore
+++ b/www/git.causal.agency/.gitignore
@@ -1,3 +1,4 @@
+*.html
 about-filter
 compress
 ctags
diff --git a/www/git.causal.agency/Makefile b/www/git.causal.agency/Makefile
index f05d4a4a..86b9f3eb 100644
--- a/www/git.causal.agency/Makefile
+++ b/www/git.causal.agency/Makefile
@@ -2,6 +2,7 @@ PREFIX = /var/www
 CONFDIR = ${PREFIX}/conf
 DATADIR = ${PREFIX}/cgit
 BINDIR = ${PREFIX}/bin
+WEBROOT = ${PREIFX}/git.causal.agency
 
 CFLAGS += -Wall -Wextra
 LDFLAGS = -static -pie
@@ -17,7 +18,9 @@ BINS += mtags
 BINS += owner-filter
 BINS += source-filter
 
-all: ${BINS}
+HTMLS = index.html
+
+all: ${BINS} ${HTMLS}
 
 compress ctags mandoc:
 	${MAKE} -C /usr/src/usr.bin/$@ LDFLAGS='${LDFLAGS}'
@@ -35,12 +38,16 @@ hilex htagml mtags:
 about-filter email-filter owner-filter source-filter: filter
 	ln -f filter $@
 
+index.html: index.7
+	mandoc -Thtml -Ostyle=https://causal.agency/style.css index.7 >index.html
+
 install: cgitrc custom.css ${BINS}
 	install -m 644 cgitrc ${CONFDIR}
 	install -m 644 custom.css ${DATADIR}
 	install -d -o www -g daemon ${PREFIX}/cache/cgit
 	install -d -m 1700 -o www -g daemon ${PREFIX}/tmp
 	install -s ${BINS} ${BINDIR}
+	install -m 644 ${HTMLS} ${WEBROOT}
 
 clean:
-	rm -f compress filter ${BINS}
+	rm -f compress filter ${BINS} ${HTMLS}
diff --git a/www/git.causal.agency/filter.c b/www/git.causal.agency/filter.c
index 9ed9ee17..7c7e9320 100644
--- a/www/git.causal.agency/filter.c
+++ b/www/git.causal.agency/filter.c
@@ -32,12 +32,8 @@ static int email(void) {
 	size_t cap = 0;
 	char *buf = NULL;
 	if (getline(&buf, &cap, stdin) < 0) err(1, "getline");
-	long x = 1;
-	for (char *ch = buf; *ch && *ch != ' '; ++ch) {
-		x *= *ch;
-	}
-	if (buf[0] == 'C' && x == 1251729952200L) {
-		printf("C.%s", buf + strcspn(buf, " "));
+	if (buf[0] == 'C' && !strncmp(&buf[strcspn(buf, " ")], " McEnroe", 8)) {
+		printf("June%s", &buf[strcspn(buf, " ")]);
 	} else {
 		printf("%s", buf);
 	}
@@ -143,6 +139,7 @@ static int source(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
+#ifdef __OpenBSD__
 	int error;
 	switch (getprogname()[0]) {
 		break; case 'a': error = pledge("stdio exec", NULL);
@@ -150,6 +147,7 @@ int main(int argc, char *argv[]) {
 		break; default:  error = pledge("stdio", NULL);
 	}
 	if (error) err(1, "pledge");
+#endif
 	switch (getprogname()[0]) {
 		case 'a': return about(argc, argv);
 		case 'e': return email();
diff --git a/www/git.causal.agency/index.7 b/www/git.causal.agency/index.7
new file mode 100644
index 00000000..58a40dfe
--- /dev/null
+++ b/www/git.causal.agency/index.7
@@ -0,0 +1,81 @@
+.Dd January 12, 2024
+.Dt GIT.CAUSAL.AGENCY 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm causal agency
+.Nd \(dqI think some people from the Gentoo project are behind this.\(dq
+.
+.Sh DESCRIPTION
+basically cgit (awful software)
+getting hammered by web crawlers
+keeps making my machine crash.
+this static page will be here
+until I can find a better solution.
+clone urls and tarball urls are still functional.
+.
+.Bl -tag
+.It src \(em dontfiles
+.Dl git clone https://git.causal.agency/src
+.It ascii.town
+.Bl -tag
+.It torus \(em collaborative ASCII art
+.Dl git clone https://git.causal.agency/torus
+.It play \(em some games for SSH
+.Dl git clone https://git.causal.agency/play
+.El
+.It email
+.Bl -tag
+.It imbox \(em IMAP to mbox
+.Dl git clone https://git.causal.agency/imbox
+.It bubger \(em IMAP archive generator
+.Dl git clone https://git.causal.agency/bubger
+.It notemap \(em notemap
+.Dl git clone https://git.causal.agency/notemap
+.El
+.It forks
+.Bl -tag
+.It shulker \(em Discord to vanilla Minecraft bridge
+.Dl git clone https://git.causal.agency/shulker
+.It cgit-pink \(em web frontend for git
+.Dl git clone https://git.causal.agency/cgit-pink
+.It dash \(em patched shell with cmake build
+.Dl git clone https://git.causal.agency/dash
+.El
+.It games
+.Bl -tag
+.It wep \(em Windows Entertainment Pack recreations
+.Dl git clone https://git.causal.agency/wep
+.It cards \(em CARDS.DLL loader for SDL
+.Dl git clone https://git.causal.agency/cards
+.El
+.It irc
+.Bl -tag
+.It scooper \(em web interface for litterbox
+.Dl git clone https://git.causal.agency/scooper
+.It litterbox \(em IRC logger
+.Dl git clone https://git.causal.agency/litterbox
+.It pounce \(em IRC bouncer
+.Dl git clone https://git.causal.agency/pounce
+.It catgirl \(em IRC client
+.Dl git clone https://git.causal.agency/catgirl
+.El
+.It ports
+.Bl -tag
+.It jorts \(em my own ports tree for macOS
+.Dl git clone https://git.causal.agency/jorts
+.It exman \(em manuals for other systems
+.Dl git clone https://git.causal.agency/exman
+.It libretls \(em libtls for OpenSSL
+.Dl git clone https://git.causal.agency/libretls
+.It ports \(em Fx and Ox ports for this software
+.Dl git clone https://git.causal.agency/ports
+.El
+.It system
+.Bl -tag
+.It kitd \(em process supervisor for OpenBSD
+.Dl git clone https://git.causal.agency/kitd
+.It catsit \(em (deprecated) process supervisor
+.Dl git clone https://git.causal.agency/catsit
+.El
+.El
diff --git a/www/photo.causal.agency/.gitignore b/www/photo.causal.agency/.gitignore
new file mode 100644
index 00000000..e6e1a830
--- /dev/null
+++ b/www/photo.causal.agency/.gitignore
@@ -0,0 +1,6 @@
+*.jpg
+*.JPG
+app.json
+posted.txt
+static/
+token.json
diff --git a/www/photo.causal.agency/0062/body b/www/photo.causal.agency/0062/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0062/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0062/date b/www/photo.causal.agency/0062/date
new file mode 100644
index 00000000..26d2ee87
--- /dev/null
+++ b/www/photo.causal.agency/0062/date
@@ -0,0 +1 @@
+April 5-6, 2025
diff --git a/www/photo.causal.agency/0062/film b/www/photo.causal.agency/0062/film
new file mode 100644
index 00000000..24c56374
--- /dev/null
+++ b/www/photo.causal.agency/0062/film
@@ -0,0 +1 @@
+Kodak UltraMax 400
diff --git a/www/photo.causal.agency/0062/lens b/www/photo.causal.agency/0062/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0062/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0063/body b/www/photo.causal.agency/0063/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0063/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0063/date b/www/photo.causal.agency/0063/date
new file mode 100644
index 00000000..c85682d5
--- /dev/null
+++ b/www/photo.causal.agency/0063/date
@@ -0,0 +1 @@
+April 6, 2025
diff --git a/www/photo.causal.agency/0063/film b/www/photo.causal.agency/0063/film
new file mode 100644
index 00000000..24c56374
--- /dev/null
+++ b/www/photo.causal.agency/0063/film
@@ -0,0 +1 @@
+Kodak UltraMax 400
diff --git a/www/photo.causal.agency/0063/lens b/www/photo.causal.agency/0063/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0063/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0064/body b/www/photo.causal.agency/0064/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0064/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0064/date b/www/photo.causal.agency/0064/date
new file mode 100644
index 00000000..f1ec6872
--- /dev/null
+++ b/www/photo.causal.agency/0064/date
@@ -0,0 +1 @@
+April 4-6, 2025
diff --git a/www/photo.causal.agency/0064/film b/www/photo.causal.agency/0064/film
new file mode 100644
index 00000000..42423702
--- /dev/null
+++ b/www/photo.causal.agency/0064/film
@@ -0,0 +1 @@
+BT21 Star 400
diff --git a/www/photo.causal.agency/0064/lens b/www/photo.causal.agency/0064/lens
new file mode 100644
index 00000000..fcf3c232
--- /dev/null
+++ b/www/photo.causal.agency/0064/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7, Yashica ML 42-75 f/3.5-4.5
diff --git a/www/photo.causal.agency/0065/body b/www/photo.causal.agency/0065/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0065/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0065/date b/www/photo.causal.agency/0065/date
new file mode 100644
index 00000000..de490c39
--- /dev/null
+++ b/www/photo.causal.agency/0065/date
@@ -0,0 +1 @@
+April 6-12, 2025
diff --git a/www/photo.causal.agency/0065/film b/www/photo.causal.agency/0065/film
new file mode 100644
index 00000000..75a90c86
--- /dev/null
+++ b/www/photo.causal.agency/0065/film
@@ -0,0 +1 @@
+Ilford FP4 Plus 125
diff --git a/www/photo.causal.agency/0065/lens b/www/photo.causal.agency/0065/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0065/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0066/body b/www/photo.causal.agency/0066/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0066/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0066/date b/www/photo.causal.agency/0066/date
new file mode 100644
index 00000000..803a4b62
--- /dev/null
+++ b/www/photo.causal.agency/0066/date
@@ -0,0 +1 @@
+April 12, 2025
diff --git a/www/photo.causal.agency/0066/film b/www/photo.causal.agency/0066/film
new file mode 100644
index 00000000..f07cfc3e
--- /dev/null
+++ b/www/photo.causal.agency/0066/film
@@ -0,0 +1 @@
+Lomography CN 400
diff --git a/www/photo.causal.agency/0066/lens b/www/photo.causal.agency/0066/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/0066/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/0067/body b/www/photo.causal.agency/0067/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0067/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0067/date b/www/photo.causal.agency/0067/date
new file mode 100644
index 00000000..bbfc292a
--- /dev/null
+++ b/www/photo.causal.agency/0067/date
@@ -0,0 +1 @@
+April 12-13, 2025
diff --git a/www/photo.causal.agency/0067/film b/www/photo.causal.agency/0067/film
new file mode 100644
index 00000000..1a1b1714
--- /dev/null
+++ b/www/photo.causal.agency/0067/film
@@ -0,0 +1 @@
+Astrum Foto 200
diff --git a/www/photo.causal.agency/0067/lens b/www/photo.causal.agency/0067/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0067/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0068/body b/www/photo.causal.agency/0068/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0068/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0068/date b/www/photo.causal.agency/0068/date
new file mode 100644
index 00000000..c460408f
--- /dev/null
+++ b/www/photo.causal.agency/0068/date
@@ -0,0 +1 @@
+April 13-17, 2025
diff --git a/www/photo.causal.agency/0068/film b/www/photo.causal.agency/0068/film
new file mode 100644
index 00000000..6227f2a9
--- /dev/null
+++ b/www/photo.causal.agency/0068/film
@@ -0,0 +1 @@
+Wolfen UN 54
diff --git a/www/photo.causal.agency/0068/lens b/www/photo.causal.agency/0068/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0068/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0069/body b/www/photo.causal.agency/0069/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0069/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0069/date b/www/photo.causal.agency/0069/date
new file mode 100644
index 00000000..939dfe29
--- /dev/null
+++ b/www/photo.causal.agency/0069/date
@@ -0,0 +1 @@
+April 17, 2025
diff --git a/www/photo.causal.agency/0069/film b/www/photo.causal.agency/0069/film
new file mode 100644
index 00000000..cb06f7ff
--- /dev/null
+++ b/www/photo.causal.agency/0069/film
@@ -0,0 +1 @@
+Konica VX 400 Super (exp. 2008)
diff --git a/www/photo.causal.agency/0069/lens b/www/photo.causal.agency/0069/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0069/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0070/body b/www/photo.causal.agency/0070/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0070/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0070/date b/www/photo.causal.agency/0070/date
new file mode 100644
index 00000000..d0bfb87b
--- /dev/null
+++ b/www/photo.causal.agency/0070/date
@@ -0,0 +1 @@
+April 18, 2025
diff --git a/www/photo.causal.agency/0070/film b/www/photo.causal.agency/0070/film
new file mode 100644
index 00000000..24e393c6
--- /dev/null
+++ b/www/photo.causal.agency/0070/film
@@ -0,0 +1 @@
+JCH Streetpan 400
diff --git a/www/photo.causal.agency/0070/lens b/www/photo.causal.agency/0070/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/0070/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/0071/body b/www/photo.causal.agency/0071/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0071/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0071/date b/www/photo.causal.agency/0071/date
new file mode 100644
index 00000000..8eaecd35
--- /dev/null
+++ b/www/photo.causal.agency/0071/date
@@ -0,0 +1 @@
+April 18-20, 2025
diff --git a/www/photo.causal.agency/0071/film b/www/photo.causal.agency/0071/film
new file mode 100644
index 00000000..d41d547a
--- /dev/null
+++ b/www/photo.causal.agency/0071/film
@@ -0,0 +1 @@
+Rollei Reinhold 640
diff --git a/www/photo.causal.agency/0071/lens b/www/photo.causal.agency/0071/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/0071/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/0072/body b/www/photo.causal.agency/0072/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0072/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0072/date b/www/photo.causal.agency/0072/date
new file mode 100644
index 00000000..8eaecd35
--- /dev/null
+++ b/www/photo.causal.agency/0072/date
@@ -0,0 +1 @@
+April 18-20, 2025
diff --git a/www/photo.causal.agency/0072/film b/www/photo.causal.agency/0072/film
new file mode 100644
index 00000000..24c56374
--- /dev/null
+++ b/www/photo.causal.agency/0072/film
@@ -0,0 +1 @@
+Kodak UltraMax 400
diff --git a/www/photo.causal.agency/0072/lens b/www/photo.causal.agency/0072/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0072/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0073/body b/www/photo.causal.agency/0073/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0073/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0073/date b/www/photo.causal.agency/0073/date
new file mode 100644
index 00000000..668a1ac5
--- /dev/null
+++ b/www/photo.causal.agency/0073/date
@@ -0,0 +1 @@
+April 20, 2025
diff --git a/www/photo.causal.agency/0073/film b/www/photo.causal.agency/0073/film
new file mode 100644
index 00000000..6968664d
--- /dev/null
+++ b/www/photo.causal.agency/0073/film
@@ -0,0 +1 @@
+Ilford Ortho Plus 80
diff --git a/www/photo.causal.agency/0073/lens b/www/photo.causal.agency/0073/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/0073/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/0074/body b/www/photo.causal.agency/0074/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0074/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0074/date b/www/photo.causal.agency/0074/date
new file mode 100644
index 00000000..0aec6293
--- /dev/null
+++ b/www/photo.causal.agency/0074/date
@@ -0,0 +1 @@
+April 20-27, 2025
diff --git a/www/photo.causal.agency/0074/film b/www/photo.causal.agency/0074/film
new file mode 100644
index 00000000..326aaee3
--- /dev/null
+++ b/www/photo.causal.agency/0074/film
@@ -0,0 +1 @@
+Wolfen NP100
diff --git a/www/photo.causal.agency/0074/lens b/www/photo.causal.agency/0074/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/0074/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/0075/body b/www/photo.causal.agency/0075/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0075/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0075/date b/www/photo.causal.agency/0075/date
new file mode 100644
index 00000000..0aec6293
--- /dev/null
+++ b/www/photo.causal.agency/0075/date
@@ -0,0 +1 @@
+April 20-27, 2025
diff --git a/www/photo.causal.agency/0075/film b/www/photo.causal.agency/0075/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/0075/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/0075/lens b/www/photo.causal.agency/0075/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0075/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0076/body b/www/photo.causal.agency/0076/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0076/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0076/date b/www/photo.causal.agency/0076/date
new file mode 100644
index 00000000..3a8a41d3
--- /dev/null
+++ b/www/photo.causal.agency/0076/date
@@ -0,0 +1 @@
+April 27, 2025
diff --git a/www/photo.causal.agency/0076/film b/www/photo.causal.agency/0076/film
new file mode 100644
index 00000000..cb06f7ff
--- /dev/null
+++ b/www/photo.causal.agency/0076/film
@@ -0,0 +1 @@
+Konica VX 400 Super (exp. 2008)
diff --git a/www/photo.causal.agency/0076/lens b/www/photo.causal.agency/0076/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0076/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0077/body b/www/photo.causal.agency/0077/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0077/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0077/date b/www/photo.causal.agency/0077/date
new file mode 100644
index 00000000..a35d7362
--- /dev/null
+++ b/www/photo.causal.agency/0077/date
@@ -0,0 +1 @@
+April 27 – May 4, 2025
diff --git a/www/photo.causal.agency/0077/film b/www/photo.causal.agency/0077/film
new file mode 100644
index 00000000..ffcc1ab6
--- /dev/null
+++ b/www/photo.causal.agency/0077/film
@@ -0,0 +1 @@
+Flic Film Aurora 400
diff --git a/www/photo.causal.agency/0077/lens b/www/photo.causal.agency/0077/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0077/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0078/body b/www/photo.causal.agency/0078/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0078/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0078/date b/www/photo.causal.agency/0078/date
new file mode 100644
index 00000000..7e2a323a
--- /dev/null
+++ b/www/photo.causal.agency/0078/date
@@ -0,0 +1 @@
+April 27 – May 3, 2025
diff --git a/www/photo.causal.agency/0078/film b/www/photo.causal.agency/0078/film
new file mode 100644
index 00000000..6a2f64b6
--- /dev/null
+++ b/www/photo.causal.agency/0078/film
@@ -0,0 +1 @@
+AristaEDU Ultra 200
diff --git a/www/photo.causal.agency/0078/lens b/www/photo.causal.agency/0078/lens
new file mode 100644
index 00000000..ad833bed
--- /dev/null
+++ b/www/photo.causal.agency/0078/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7, Yashica ML Macro 55mm f/2.8
diff --git a/www/photo.causal.agency/0079/body b/www/photo.causal.agency/0079/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/0079/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/0079/date b/www/photo.causal.agency/0079/date
new file mode 100644
index 00000000..d44c408e
--- /dev/null
+++ b/www/photo.causal.agency/0079/date
@@ -0,0 +1 @@
+May 3, 2025
diff --git a/www/photo.causal.agency/0079/film b/www/photo.causal.agency/0079/film
new file mode 100644
index 00000000..7438f38e
--- /dev/null
+++ b/www/photo.causal.agency/0079/film
@@ -0,0 +1 @@
+Lucky SHD 400
diff --git a/www/photo.causal.agency/0079/lens b/www/photo.causal.agency/0079/lens
new file mode 100644
index 00000000..197595bc
--- /dev/null
+++ b/www/photo.causal.agency/0079/lens
@@ -0,0 +1 @@
+Yashica ML Macro 55mm f/2.8
diff --git a/www/photo.causal.agency/0080/body b/www/photo.causal.agency/0080/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/0080/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/0080/date b/www/photo.causal.agency/0080/date
new file mode 100644
index 00000000..17eb8868
--- /dev/null
+++ b/www/photo.causal.agency/0080/date
@@ -0,0 +1 @@
+May 4-14, 2025
diff --git a/www/photo.causal.agency/0080/film b/www/photo.causal.agency/0080/film
new file mode 100644
index 00000000..a87ca638
--- /dev/null
+++ b/www/photo.causal.agency/0080/film
@@ -0,0 +1 @@
+Konica 400 VX Super (exp. 2005)
diff --git a/www/photo.causal.agency/0080/lens b/www/photo.causal.agency/0080/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/0080/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/0080/note b/www/photo.causal.agency/0080/note
new file mode 100644
index 00000000..72945eda
--- /dev/null
+++ b/www/photo.causal.agency/0080/note
@@ -0,0 +1,3 @@
+first roll I didn't even have the lab scan as a backup!
+shot at EI 100 and clearly overexposed.
+is the one-stop-per-decade rule even real?
diff --git a/www/photo.causal.agency/2024-04-10/IMG_0832.txt b/www/photo.causal.agency/2024-04-10/IMG_0832.txt
new file mode 100644
index 00000000..65724024
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-10/IMG_0832.txt
@@ -0,0 +1,6 @@
+a red brick wall with some faded black graffiti.
+in the lower third, some bricks are missing
+from the outer layer in an arc shape.
+along the bottom is a ledge of conrete
+lightly covered in brick dust and chunks
+below the missing areas above.
diff --git a/www/photo.causal.agency/2024-04-10/IMG_0850.txt b/www/photo.causal.agency/2024-04-10/IMG_0850.txt
new file mode 100644
index 00000000..4cbb3def
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-10/IMG_0850.txt
@@ -0,0 +1,6 @@
+grey steel beams of a building in early construction
+on a background of blue sky with some light clouds.
+the beams are intersecting at odd points,
+implying the final building will not be a simple box.
+the sun casts dark shadows into the interiors
+of the I-shaped metal.
diff --git a/www/photo.causal.agency/2024-04-10/IMG_0852.txt b/www/photo.causal.agency/2024-04-10/IMG_0852.txt
new file mode 100644
index 00000000..707d7cd6
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-10/IMG_0852.txt
@@ -0,0 +1,4 @@
+in the foreground, a metal construction fence.
+behind that, the bright red arm of a sort of small crane.
+the arm is horizontal and crushing a perpendicular piece of fence,
+which has deformed smoothly under it.
diff --git a/www/photo.causal.agency/2024-04-10/IMG_0858.txt b/www/photo.causal.agency/2024-04-10/IMG_0858.txt
new file mode 100644
index 00000000..42f243e4
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-10/IMG_0858.txt
@@ -0,0 +1,6 @@
+an uneven grid of old wooden-framed windows in an alley.
+the red paint on the frames is peeling badly,
+completely stripped in some spots.
+in the reflections of the lower windows
+we see the roofs of the opposite buildings
+and hints of clouds in the sky.
diff --git a/www/photo.causal.agency/2024-04-10/IMG_0859.txt b/www/photo.causal.agency/2024-04-10/IMG_0859.txt
new file mode 100644
index 00000000..ca33d7e0
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-10/IMG_0859.txt
@@ -0,0 +1,6 @@
+an old backetball hoop mounted in an alley.
+the backboard has been graffitied
+and vines have invaded.
+a few red strands of net are left hanging from the hoop.
+the fence behind is painted with a design of yellow, purple, white and blue.
+it's the kind of hoop airbud might be hanging around.
diff --git a/www/photo.causal.agency/2024-04-10/IMG_0865.txt b/www/photo.causal.agency/2024-04-10/IMG_0865.txt
new file mode 100644
index 00000000..7a955fc2
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-10/IMG_0865.txt
@@ -0,0 +1,2 @@
+deep tire tread pressed into mud in the center of an alley.
+a small branch of evergreen lies to one side.
diff --git a/www/photo.causal.agency/2024-04-10/IMG_0890.txt b/www/photo.causal.agency/2024-04-10/IMG_0890.txt
new file mode 100644
index 00000000..9d2cdc43
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-10/IMG_0890.txt
@@ -0,0 +1,9 @@
+a pipe coming out of a light brown brick wall.
+the pipe comes out of a metal square in the centre of the wall,
+travels up and left for a bit,
+before continuing straight up out of frame.
+opposite, in the bottom right,
+is the top of a red metal grate in front
+of a ground-level window.
+the brick below where the pipe enters the wall
+is stained dark.
diff --git a/www/photo.causal.agency/2024-04-14/IMG_1054.txt b/www/photo.causal.agency/2024-04-14/IMG_1054.txt
new file mode 100644
index 00000000..f4803ee2
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-14/IMG_1054.txt
@@ -0,0 +1,5 @@
+a short wall of natural rock,
+all broken up somewhat neatly
+along horizontal and vertical lines.
+most of the rock is cool grey,
+while some parts are warm brown.
diff --git a/www/photo.causal.agency/2024-04-14/IMG_1058.txt b/www/photo.causal.agency/2024-04-14/IMG_1058.txt
new file mode 100644
index 00000000..21aeb189
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-14/IMG_1058.txt
@@ -0,0 +1,6 @@
+moss on a bit of exposed natural rock
+surrounded by mostly brown grass.
+there is shorter, darker green and brown moss,
+as well as longer lighter green moss.
+some small pieces of the rock are broken off
+and lay in little piles.
diff --git a/www/photo.causal.agency/2024-04-14/IMG_1066.txt b/www/photo.causal.agency/2024-04-14/IMG_1066.txt
new file mode 100644
index 00000000..81747287
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-14/IMG_1066.txt
@@ -0,0 +1,10 @@
+two green buds on the end of a thin branch
+on a blurry brown backdrop.
+the branch enters the frame
+from the bottom left corner,
+and there are three other pairs of buds
+along it,
+out of focus.
+there is a hint of another bebudded branch
+in the background,
+but there is otherwise very little green.
diff --git a/www/photo.causal.agency/2024-04-19/IMG_1158.txt b/www/photo.causal.agency/2024-04-19/IMG_1158.txt
new file mode 100644
index 00000000..e18bd6c7
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-19/IMG_1158.txt
@@ -0,0 +1,6 @@
+a glowing amber street lamp
+affixed to a telephone pole.
+across its round top
+there is peeling grey-brown paint.
+the lamp is surrounded
+by out of focus bare tree branches.
diff --git a/www/photo.causal.agency/2024-04-20/IMG_1225.txt b/www/photo.causal.agency/2024-04-20/IMG_1225.txt
new file mode 100644
index 00000000..525a4bf3
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-20/IMG_1225.txt
@@ -0,0 +1,8 @@
+close up of a squirrel atop a dark wood fence.
+its tail is curled on its back
+and it's facing left but looking at the camera.
+there are crumbs of dirt
+around its mouth and whiskers.
+you can see the little claws
+of its front paw in the foreground,
+while the other paw is curled to its chest.
diff --git a/www/photo.causal.agency/2024-04-20/IMG_1234.txt b/www/photo.causal.agency/2024-04-20/IMG_1234.txt
new file mode 100644
index 00000000..faee1be9
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-20/IMG_1234.txt
@@ -0,0 +1,8 @@
+a pigeon standing upright on some concrete.
+it's a usual grey city pigeon,
+with a mix of light and dark feathers
+on its wings,
+purple and green areas up its neck,
+and red feet.
+in the blurred background
+another pigeon is strutting past.
diff --git a/www/photo.causal.agency/2024-04-20/IMG_1245.txt b/www/photo.causal.agency/2024-04-20/IMG_1245.txt
new file mode 100644
index 00000000..c971da91
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-20/IMG_1245.txt
@@ -0,0 +1,17 @@
+a tall shot of the back of a beautifully coloured building.
+the brick wall has been painted a sort of pink,
+or at least it's faded to that colour.
+there is a splotch in the middle
+where the paint has worn off the brick,
+along with some stray bricks
+elsewhere that have been replaced.
+the spiral stairs descending
+from the back balconies of two floors
+have also been painted red,
+but have faded to pink
+closer to the top.
+everything is a little crooked.
+the old wooden-framed windows
+on the left,
+the more recently replaced doors,
+and the balconies.
diff --git a/www/photo.causal.agency/2024-04-20/IMG_1253.txt b/www/photo.causal.agency/2024-04-20/IMG_1253.txt
new file mode 100644
index 00000000..5158c533
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-20/IMG_1253.txt
@@ -0,0 +1,7 @@
+a CCTV camera on the corner
+of a black corrugated metal building.
+it's mounted on a beige rusting bracket
+coming off the wall at a right angle.
+it's an old-style boxy camera
+with a little hood.
+who knows if it's still connected to anything?
diff --git a/www/photo.causal.agency/2024-04-20/IMG_1254.txt b/www/photo.causal.agency/2024-04-20/IMG_1254.txt
new file mode 100644
index 00000000..4780f8b5
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-20/IMG_1254.txt
@@ -0,0 +1,8 @@
+a white pigeon walking in a paved alley.
+its visible eye is a beautiful dark orange,
+slightly lighter around its pupil.
+its mostly white plumage
+is dotted here and there by darker feathers,
+and its tail feathers in particular are dark.
+there's a hint of small green feathers
+around its neck.
diff --git a/www/photo.causal.agency/2024-04-30/IMG_1619.txt b/www/photo.causal.agency/2024-04-30/IMG_1619.txt
new file mode 100644
index 00000000..27f87311
--- /dev/null
+++ b/www/photo.causal.agency/2024-04-30/IMG_1619.txt
@@ -0,0 +1,8 @@
+the seat of a rusted metal stool out in the way
+with a shallow pool of water on it.
+in the center is a handle-shaped hole,
+which is raised slightly,
+causing the water to pool further
+around the edges.
+there is a single fallen light green tree bud
+just near the hole.
diff --git a/www/photo.causal.agency/2024-05-03/IMG_1684.txt b/www/photo.causal.agency/2024-05-03/IMG_1684.txt
new file mode 100644
index 00000000..08624d6e
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-03/IMG_1684.txt
@@ -0,0 +1,7 @@
+a yellow-and-red flower.
+I don't know types of flowers.
+the petals are yellow and red,
+the colours flecked in each other
+like you would see on an apple.
+the tops of the petals have
+toothy looking bits.
diff --git a/www/photo.causal.agency/2024-05-03/IMG_1692.txt b/www/photo.causal.agency/2024-05-03/IMG_1692.txt
new file mode 100644
index 00000000..182319f2
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-03/IMG_1692.txt
@@ -0,0 +1,4 @@
+a pair of discarded shoes
+on the ground next to a black trash bag.
+the shoes are chunky running shoes,
+white at the front and baby blue at the back.
diff --git a/www/photo.causal.agency/2024-05-03/IMG_1706.txt b/www/photo.causal.agency/2024-05-03/IMG_1706.txt
new file mode 100644
index 00000000..d325d518
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-03/IMG_1706.txt
@@ -0,0 +1,4 @@
+a square window
+in the centre of a concrete wall
+covered in vines
+that haven't started growing leaves again yet.
diff --git a/www/photo.causal.agency/2024-05-03/IMG_1724.txt b/www/photo.causal.agency/2024-05-03/IMG_1724.txt
new file mode 100644
index 00000000..2dd5bb3d
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-03/IMG_1724.txt
@@ -0,0 +1,3 @@
+a telephone pole
+against a blue sky with some light clouds,
+cables coming off it in each diagonal.
diff --git a/www/photo.causal.agency/2024-05-03/IMG_1730.txt b/www/photo.causal.agency/2024-05-03/IMG_1730.txt
new file mode 100644
index 00000000..ca51034b
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-03/IMG_1730.txt
@@ -0,0 +1,9 @@
+a selfie taken in
+a particularly reflective window on the street,
+giving everything a slightly offset doubled look
+from the layers of glass.
+I'm wearing a red and purple floral patterned dress
+and a green jacket.
+I have red hair
+and I'm holding a canon DSLR
+up to my face.
diff --git a/www/photo.causal.agency/2024-05-03/IMG_1748.txt b/www/photo.causal.agency/2024-05-03/IMG_1748.txt
new file mode 100644
index 00000000..29bc3a76
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-03/IMG_1748.txt
@@ -0,0 +1,4 @@
+some kind of short tree
+spilling over tthe top of an alley wooden fence.
+its branches have thorns
+and are just started to grow leaves.
diff --git a/www/photo.causal.agency/2024-05-06/IMG_1951.txt b/www/photo.causal.agency/2024-05-06/IMG_1951.txt
new file mode 100644
index 00000000..78fe46a7
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-06/IMG_1951.txt
@@ -0,0 +1,12 @@
+the top cube of a brutalist house,
+with one small window
+in each the centre of each face.
+the left face of the cube
+has an overhang above
+which continues down the side.
+the concrete has large curved grooves
+scattered over its surface.
+the sun is hitting the left face,
+shadowed by the overhang.
+behind the cube is a blue sky
+with scattered clouds.
diff --git a/www/photo.causal.agency/2024-05-06/IMG_1969.txt b/www/photo.causal.agency/2024-05-06/IMG_1969.txt
new file mode 100644
index 00000000..6276a710
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-06/IMG_1969.txt
@@ -0,0 +1,7 @@
+some kind of black bird
+in the grass
+holding a grub of some kind
+in its beak.
+it has purple and green
+in its feathers similar to a pigeon,
+with some white streaks on its wings.
diff --git a/www/photo.causal.agency/2024-05-06/IMG_1973.txt b/www/photo.causal.agency/2024-05-06/IMG_1973.txt
new file mode 100644
index 00000000..b23e190b
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-06/IMG_1973.txt
@@ -0,0 +1,3 @@
+a black bird standing in the grass
+with something small in its beak.
+its black feathers are spotted with white.
diff --git a/www/photo.causal.agency/2024-05-06/IMG_1996.txt b/www/photo.causal.agency/2024-05-06/IMG_1996.txt
new file mode 100644
index 00000000..ddbc0a2b
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-06/IMG_1996.txt
@@ -0,0 +1,4 @@
+a standard issue city pigeon
+viewed from the side,
+standing atop a wooden fence
+with a blurred brick wall behind it.
diff --git a/www/photo.causal.agency/2024-05-06/IMG_1998.txt b/www/photo.causal.agency/2024-05-06/IMG_1998.txt
new file mode 100644
index 00000000..42cf62cc
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-06/IMG_1998.txt
@@ -0,0 +1,3 @@
+a standard issue city pigeon
+standing on the corner of a balcony
+with the railing behind it.
diff --git a/www/photo.causal.agency/2024-05-06/IMG_2009.txt b/www/photo.causal.agency/2024-05-06/IMG_2009.txt
new file mode 100644
index 00000000..60518f52
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-06/IMG_2009.txt
@@ -0,0 +1,4 @@
+a squirrel on the trunk of a tree,
+its body facing down
+and its head lifted towards the camera.
+ones of its paws is stretched out to the side.
diff --git a/www/photo.causal.agency/2024-05-06/IMG_2015.txt b/www/photo.causal.agency/2024-05-06/IMG_2015.txt
new file mode 100644
index 00000000..48494b77
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-06/IMG_2015.txt
@@ -0,0 +1,4 @@
+a standard issue city pigeon
+on a telephone cable
+in front of a brick wall,
+looking directly at the camera.
diff --git a/www/photo.causal.agency/2024-05-31/IMG_2078.txt b/www/photo.causal.agency/2024-05-31/IMG_2078.txt
new file mode 100644
index 00000000..5a08757c
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-31/IMG_2078.txt
@@ -0,0 +1,5 @@
+the side of a school building at sunset.
+the sun is hitting the top corner.
+on the left is the brick wall,
+in the centre there are two floors of windows,
+and on the right there are green trees.
diff --git a/www/photo.causal.agency/2024-05-31/IMG_2079.txt b/www/photo.causal.agency/2024-05-31/IMG_2079.txt
new file mode 100644
index 00000000..d88645c5
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-31/IMG_2079.txt
@@ -0,0 +1,7 @@
+the top of a theatre building at sunset.
+the top has a row of frosted glass windows
+with an unfrosted silhouette
+of a man sitting on a ladder.
+below the windows there's a white
+swirly teardrop pattern,
+which continues down into the shadow of the setting sun.
diff --git a/www/photo.causal.agency/2024-05-31/IMG_2084.txt b/www/photo.causal.agency/2024-05-31/IMG_2084.txt
new file mode 100644
index 00000000..b8ed4fc5
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-31/IMG_2084.txt
@@ -0,0 +1,4 @@
+a building of many intersecting shapes
+at sunset.
+brick, glass and concrete.
+only the top of the building is in direct sunlight.
diff --git a/www/photo.causal.agency/2024-05-31/IMG_2103.txt b/www/photo.causal.agency/2024-05-31/IMG_2103.txt
new file mode 100644
index 00000000..26b1e1cd
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-31/IMG_2103.txt
@@ -0,0 +1,8 @@
+a high-rise apartment building at sunset.
+the sun is hitting its left red brick side,
+which is broken up by white stripes
+between each floor.
+the front of the building
+has windows and balconies.
+some of the balconies near the top
+have people out on them.
diff --git a/www/photo.causal.agency/2024-05-31/IMG_2114.txt b/www/photo.causal.agency/2024-05-31/IMG_2114.txt
new file mode 100644
index 00000000..7702a374
--- /dev/null
+++ b/www/photo.causal.agency/2024-05-31/IMG_2114.txt
@@ -0,0 +1,6 @@
+a high-rise apartment building
+during or maybe just after sunset.
+in the light it appears beige.
+there is a row of balconies
+going up the side of the building,
+off-centre.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-009A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-009A.txt
new file mode 100644
index 00000000..7affb93a
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-009A.txt
@@ -0,0 +1,9 @@
+a view down an alley
+with the backs of buildings on the left
+and greenery on the right and above.
+right at the end of the alley
+some people are walking past.
+the top of the frame is over-exposed.
+the lens is focused at infinity
+down the length of the alley,
+which gives an interesting effect.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-011A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-011A.txt
new file mode 100644
index 00000000..4628a2c2
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-011A.txt
@@ -0,0 +1,6 @@
+a little wooden house(?) hanging from a tree.
+it's something you'd expect to have a lantern inside,
+I think.
+3 by 3 paned sides and a little overhanging roof.
+behind it is a wooden fence
+lightly covered in leaves.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-012A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-012A.txt
new file mode 100644
index 00000000..aabe2b40
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-012A.txt
@@ -0,0 +1,9 @@
+an old friend:
+the pipe coming out of a square patch
+in a yellow brick wall
+that I've photographed before on digital.
+the pipe comes out at an angle
+towards the top left
+then straightens out towards the top of the frame.
+in the bottom right
+there's the top of a window grate.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-015A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-015A.txt
new file mode 100644
index 00000000..57fb909b
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-015A.txt
@@ -0,0 +1,6 @@
+some pretty red-pink flowers
+on a tree in an alley
+growing over a wooden fence.
+one branch is in focus in the foreground,
+the rest are pleasantly blurred
+with a little bit of swirl.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-016A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-016A.txt
new file mode 100644
index 00000000..a5bb9fa0
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-016A.txt
@@ -0,0 +1,5 @@
+a concrete step out a back door into an alley.
+the top and near side of the step
+are covered in some kind of green.
+I don't know if that's a moss
+or something else.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-020A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-020A.txt
new file mode 100644
index 00000000..5da2a186
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-020A.txt
@@ -0,0 +1,12 @@
+the side of a weird old
+presumably european
+tiny car that's been rotting
+in an alley for who knows how long.
+the car is painted black
+and there's a bunch of graffiti in white
+on the door and back side
+as well as the window.
+on the door next to the handle
+there's a stenciled "GREMA".
+behind the car is a wooden fence
+with some deep green vines.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-024A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-024A.txt
new file mode 100644
index 00000000..d82ec10e
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-024A.txt
@@ -0,0 +1,5 @@
+a view down an alley
+with wooden fences along both sides
+and lots of greenery spilling over them,
+out of their bases,
+and hanging from above.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-026A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-026A.txt
new file mode 100644
index 00000000..e891695b
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-026A.txt
@@ -0,0 +1,2 @@
+some puffy pink flowers hanging from a tree
+amid wooden fences covered in vines.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-028A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-028A.txt
new file mode 100644
index 00000000..dd732a64
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-028A.txt
@@ -0,0 +1,5 @@
+an old friend:
+a boxy security camera
+mounted on the corner of
+a black corrugated metal wall.
+lots of green trees behind it.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-030A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-030A.txt
new file mode 100644
index 00000000..f8be350d
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-030A.txt
@@ -0,0 +1,7 @@
+a familiar sight:
+the back of a brick building
+painted in red
+and fading unevenly to pink.
+a spiral staircase descends
+past three doors on the right,
+and there are three windows on the left.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-031A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-031A.txt
new file mode 100644
index 00000000..3614056a
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-031A.txt
@@ -0,0 +1,7 @@
+another familiar sight:
+an old basketball hoop
+mounted against a wooden fence
+in an alley,
+vines growing over the backboard
+and scraps of netting
+hanging from the rim.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-032A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-032A.txt
new file mode 100644
index 00000000..24678e0f
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-032A.txt
@@ -0,0 +1,7 @@
+an askew lantern hanging
+next to a telephone pole.
+it's hanging by its hat,
+but its body is crooked.
+there's some rope hanging next to it,
+and there's some christmas lights
+looped around the telephone pole.
diff --git a/www/photo.causal.agency/2024-06-08/R1-07534-036A.txt b/www/photo.causal.agency/2024-06-08/R1-07534-036A.txt
new file mode 100644
index 00000000..b9fbf500
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/R1-07534-036A.txt
@@ -0,0 +1,12 @@
+a selfie in a convex mirror
+mounted on a telephone pole.
+I appear quite small in the mirror.
+I'm standing in front
+of a building with
+colourful graffiti on it.
+behind the mirror
+is a yellow diamond road sign,
+and on the side of the pole
+is a no trash sign
+with a fine of up to $1000.
+behind is a blue cloudy sky.
diff --git a/www/photo.causal.agency/2024-06-08/film b/www/photo.causal.agency/2024-06-08/film
new file mode 100644
index 00000000..0555f564
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/film
@@ -0,0 +1 @@
+Fujifilm 400
diff --git a/www/photo.causal.agency/2024-06-08/lens b/www/photo.causal.agency/2024-06-08/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-08/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-002A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-002A.txt
new file mode 100644
index 00000000..a233035e
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-002A.txt
@@ -0,0 +1,14 @@
+the bottom of a spiral fire escape
+black metal stair.
+there's a piece of stone or concrete
+at the bottom
+with green moss growing on its edges.
+the surrounding ground
+is covered in dead leaves and such.
+there's a peculiar orange-ish
+mark that runs down
+the middle right side of the frame
+and wanders back and forth a little.
+don't know what's up with that
+and this is the only shot
+on the roll with it.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-003A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-003A.txt
new file mode 100644
index 00000000..db048266
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-003A.txt
@@ -0,0 +1,6 @@
+a short, wide factory-looking window
+in a dark brick wall behind a fence.
+many of the panes of glass are broken.
+honestly I'm posting this photo
+because I want to take it again
+on black & white film.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-007A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-007A.txt
new file mode 100644
index 00000000..c6e673d9
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-007A.txt
@@ -0,0 +1,5 @@
+a painted red metal fire escape spiral staircase
+climbing up the side of a narrow brick building.
+it goes all the way to the roof,
+where it becomes over-exposed
+and starts to blend into the sky behind it.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-009A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-009A.txt
new file mode 100644
index 00000000..fa47b704
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-009A.txt
@@ -0,0 +1,7 @@
+a telephone pole covered in paintball paint
+(I assume)
+in front of a brick wall.
+towards the bottom
+there are more red spots
+and towards the top
+there are more blue.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-010A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-010A.txt
new file mode 100644
index 00000000..c71a81ac
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-010A.txt
@@ -0,0 +1,8 @@
+pink flowers
+on a tree with green leaves
+against a bright blue sky.
+the contrast in colours
+between the pink, green and blue
+really pops.
+this is my favourite shot
+on the roll.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-012A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-012A.txt
new file mode 100644
index 00000000..5d2096fa
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-012A.txt
@@ -0,0 +1,3 @@
+a green metal staircase
+viewed as if about to climb it,
+hugging the back of a brick building.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-013A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-013A.txt
new file mode 100644
index 00000000..56d6d814
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-013A.txt
@@ -0,0 +1,7 @@
+a pink flower
+with a yellow centre
+and a couple of its friends
+on a pleasantly blurred
+background of the green bush
+its growing from
+and a bit of a brick wall.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-015A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-015A.txt
new file mode 100644
index 00000000..a3cb3fcf
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-015A.txt
@@ -0,0 +1,4 @@
+a plump light pink flower
+with really dense petal arrangement
+on a blurred background
+of dark green leaves.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-016A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-016A.txt
new file mode 100644
index 00000000..7c94196c
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-016A.txt
@@ -0,0 +1,4 @@
+a pile of old bricks in the sunlight.
+some of the faces of the bricks are painted grey-blue.
+this is another one I'd love to take again
+on black & white film.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-029A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-029A.txt
new file mode 100644
index 00000000..c4383804
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-029A.txt
@@ -0,0 +1,4 @@
+a wooden fence
+with vines growing across it
+and two steps fixed to the side of it.
+for cats to jump up, I suppose.
diff --git a/www/photo.causal.agency/2024-06-12/R1-07671-031A.txt b/www/photo.causal.agency/2024-06-12/R1-07671-031A.txt
new file mode 100644
index 00000000..12b5fc48
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/R1-07671-031A.txt
@@ -0,0 +1,4 @@
+an overgrown back yard
+with a metal staircase
+descending into it,
+viewed from under a tree.
diff --git a/www/photo.causal.agency/2024-06-12/film b/www/photo.causal.agency/2024-06-12/film
new file mode 100644
index 00000000..0555f564
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/film
@@ -0,0 +1 @@
+Fujifilm 400
diff --git a/www/photo.causal.agency/2024-06-12/lens b/www/photo.causal.agency/2024-06-12/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-12/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-06-22/000093910004.txt b/www/photo.causal.agency/2024-06-22/000093910004.txt
new file mode 100644
index 00000000..d5678989
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910004.txt
@@ -0,0 +1,5 @@
+the trunk of a large tree,
+with two hefty branches
+splitting off.
+the bark is in vertical lines
+with deep texture.
diff --git a/www/photo.causal.agency/2024-06-22/000093910008.txt b/www/photo.causal.agency/2024-06-22/000093910008.txt
new file mode 100644
index 00000000..33e1f56d
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910008.txt
@@ -0,0 +1,3 @@
+a piece of stone on the ground
+with moss growing in a little
+indent in its side.
diff --git a/www/photo.causal.agency/2024-06-22/000093910009.txt b/www/photo.causal.agency/2024-06-22/000093910009.txt
new file mode 100644
index 00000000..d67283fe
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910009.txt
@@ -0,0 +1,7 @@
+Ayla in a light coloured tshirt,
+short jorts,
+small backpack,
+white baseball cap
+from behind walking up stone steps
+towards a small stone building
+with a green door.
diff --git a/www/photo.causal.agency/2024-06-22/000093910014.txt b/www/photo.causal.agency/2024-06-22/000093910014.txt
new file mode 100644
index 00000000..1d61a0ca
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910014.txt
@@ -0,0 +1,4 @@
+a stone path
+leading towards
+stone steps leading up
+surrounded by trees.
diff --git a/www/photo.causal.agency/2024-06-22/000093910015.txt b/www/photo.causal.agency/2024-06-22/000093910015.txt
new file mode 100644
index 00000000..8dfe4fdc
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910015.txt
@@ -0,0 +1,4 @@
+a view of the montreal skyline
+from the lookout on the mountain.
+the sky is white.
+there is so much film grain.
diff --git a/www/photo.causal.agency/2024-06-22/000093910016.txt b/www/photo.causal.agency/2024-06-22/000093910016.txt
new file mode 100644
index 00000000..b47910ee
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910016.txt
@@ -0,0 +1,2 @@
+a pile of discarded ductwork
+and scraps of wood.
diff --git a/www/photo.causal.agency/2024-06-22/000093910017.txt b/www/photo.causal.agency/2024-06-22/000093910017.txt
new file mode 100644
index 00000000..c96be2fc
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910017.txt
@@ -0,0 +1,3 @@
+vines on a telephone pole
+in front of a brick building
+painted blue.
diff --git a/www/photo.causal.agency/2024-06-22/000093910019.txt b/www/photo.causal.agency/2024-06-22/000093910019.txt
new file mode 100644
index 00000000..1fc0cccf
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910019.txt
@@ -0,0 +1,5 @@
+a selfie in a convex mirror.
+the mirror is off to the top right.
+I'm wearing a green shirt.
+behind me is a somewhat decaying
+short brick building.
diff --git a/www/photo.causal.agency/2024-06-22/000093910021.txt b/www/photo.causal.agency/2024-06-22/000093910021.txt
new file mode 100644
index 00000000..e8e23272
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910021.txt
@@ -0,0 +1,6 @@
+a mismatched arrangement
+of rectangular window panes
+in a space roughly the size
+of a garage door.
+it is being slowly reclaimed
+by vines and bushes.
diff --git a/www/photo.causal.agency/2024-06-22/000093910022.txt b/www/photo.causal.agency/2024-06-22/000093910022.txt
new file mode 100644
index 00000000..6040fbc9
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910022.txt
@@ -0,0 +1,4 @@
+a view up between two buildings
+at a metal truss in silhouette
+against the almost white sky
+and some cables running between them.
diff --git a/www/photo.causal.agency/2024-06-22/000093910023.txt b/www/photo.causal.agency/2024-06-22/000093910023.txt
new file mode 100644
index 00000000..1313869d
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910023.txt
@@ -0,0 +1,4 @@
+moss and little plants
+growing on pavement in an alley
+at the base of rusty metal stairs,
+behind which is a large shallow puddle.
diff --git a/www/photo.causal.agency/2024-06-22/000093910026.txt b/www/photo.causal.agency/2024-06-22/000093910026.txt
new file mode 100644
index 00000000..2a6f4f9f
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910026.txt
@@ -0,0 +1,10 @@
+a set of metal doors
+in a blue brick building
+with what looks like a big duct pipe
+above them.
+it's not attached to anything
+it's just sitting over the doors
+like a giant unibrow.
+there is a little bridge leading towards the doors.
+to the right of the doors
+is the address number 2111.
diff --git a/www/photo.causal.agency/2024-06-22/000093910027.txt b/www/photo.causal.agency/2024-06-22/000093910027.txt
new file mode 100644
index 00000000..fb69223e
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910027.txt
@@ -0,0 +1,2 @@
+a cat in an alley,
+looking off to the left.
diff --git a/www/photo.causal.agency/2024-06-22/000093910031.txt b/www/photo.causal.agency/2024-06-22/000093910031.txt
new file mode 100644
index 00000000..b9c53122
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910031.txt
@@ -0,0 +1,3 @@
+a set of metal fence doors
+blocking a double-wide staircase
+up the side of a building.
diff --git a/www/photo.causal.agency/2024-06-22/000093910032.txt b/www/photo.causal.agency/2024-06-22/000093910032.txt
new file mode 100644
index 00000000..a0d13629
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/000093910032.txt
@@ -0,0 +1,10 @@
+natural gas pipework
+on a beige brick wall.
+there is a line of pipe
+going horizontal across
+the bottom of the frame,
+with one pipe coming off
+in the middle
+and going upwards,
+with a zig-zag
+and then continuing up at an angle.
diff --git a/www/photo.causal.agency/2024-06-22/film b/www/photo.causal.agency/2024-06-22/film
new file mode 100644
index 00000000..97a445ae
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/film
@@ -0,0 +1 @@
+Shanghai Color Film 400
diff --git a/www/photo.causal.agency/2024-06-22/lens b/www/photo.causal.agency/2024-06-22/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-22/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-06-25/000099820005.txt b/www/photo.causal.agency/2024-06-25/000099820005.txt
new file mode 100644
index 00000000..4f1f8d0d
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820005.txt
@@ -0,0 +1,8 @@
+the side of a building
+that's been covered in
+some sort of construction fabric,
+perhaps tyvek,
+then had horizontal boards of wood
+nailed over it.
+the fabric is torn in places
+and hanging down over itself.
diff --git a/www/photo.causal.agency/2024-06-25/000099820006.txt b/www/photo.causal.agency/2024-06-25/000099820006.txt
new file mode 100644
index 00000000..8cd526f2
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820006.txt
@@ -0,0 +1,7 @@
+the front of a large apartment block
+under construction
+which hasn't yet
+had its exterior wall installed.
+there are balcony platforms
+jutting out from the building
+with no walls or railings.
diff --git a/www/photo.causal.agency/2024-06-25/000099820008.txt b/www/photo.causal.agency/2024-06-25/000099820008.txt
new file mode 100644
index 00000000..05293f76
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820008.txt
@@ -0,0 +1,9 @@
+a backyard with spiral staircase
+descending into it,
+a wooden fence
+and brick dividing wall,
+lights hanging between
+the staircase and somewhere unseen.
+the back door
+has a small "beware of dog" sign
+in the bottom corner.
diff --git a/www/photo.causal.agency/2024-06-25/000099820010.txt b/www/photo.causal.agency/2024-06-25/000099820010.txt
new file mode 100644
index 00000000..e256a668
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820010.txt
@@ -0,0 +1,9 @@
+a low,
+short and wide
+window into a basement
+in a stone wall.
+there is a metal grate
+in front of the window
+with a pattern of three
+sideways H shapes
+separated by straight vertical bars.
diff --git a/www/photo.causal.agency/2024-06-25/000099820011.txt b/www/photo.causal.agency/2024-06-25/000099820011.txt
new file mode 100644
index 00000000..d04f2e30
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820011.txt
@@ -0,0 +1,10 @@
+a small horizontal metal door
+in a plaster wall
+with very flaky paint.
+there are two holes
+in the small door,
+a smaller one in the top left
+and a larger one in the bottom right.
+there are stars,
+possibly stickers,
+placed around the opening.
diff --git a/www/photo.causal.agency/2024-06-25/000099820012.txt b/www/photo.causal.agency/2024-06-25/000099820012.txt
new file mode 100644
index 00000000..03064297
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820012.txt
@@ -0,0 +1,3 @@
+four large flexible fabric tubes
+coming out of various windows
+in the side of a school building.
diff --git a/www/photo.causal.agency/2024-06-25/000099820013.txt b/www/photo.causal.agency/2024-06-25/000099820013.txt
new file mode 100644
index 00000000..f46ce8c0
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820013.txt
@@ -0,0 +1,7 @@
+the top of a building
+where a weirdly small
+cube sticks up above
+the rest of the roof,
+with a full size window
+in the side.
+cloudy sky behind the protrusion.
diff --git a/www/photo.causal.agency/2024-06-25/000099820018.txt b/www/photo.causal.agency/2024-06-25/000099820018.txt
new file mode 100644
index 00000000..cfd4089a
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820018.txt
@@ -0,0 +1,5 @@
+a cat sitting up
+in the open window
+of a weird tall garage extension type thing.
+its fur is sticking through the chicken wire
+that covers the bottom half of the window.
diff --git a/www/photo.causal.agency/2024-06-25/000099820019.txt b/www/photo.causal.agency/2024-06-25/000099820019.txt
new file mode 100644
index 00000000..b9c2a31a
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820019.txt
@@ -0,0 +1,2 @@
+an automatic sprinkler fire alarm
+on an external brick wall.
diff --git a/www/photo.causal.agency/2024-06-25/000099820022.txt b/www/photo.causal.agency/2024-06-25/000099820022.txt
new file mode 100644
index 00000000..4dd6cc34
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820022.txt
@@ -0,0 +1,4 @@
+a flat trolley
+with rope sitting on it.
+the floor of the trolley
+is warped upwards.
diff --git a/www/photo.causal.agency/2024-06-25/000099820023.txt b/www/photo.causal.agency/2024-06-25/000099820023.txt
new file mode 100644
index 00000000..ce39c313
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820023.txt
@@ -0,0 +1,3 @@
+a view into the interior courtyard
+of an abandoned building
+with a haphazardly boarded up window.
diff --git a/www/photo.causal.agency/2024-06-25/000099820026.txt b/www/photo.causal.agency/2024-06-25/000099820026.txt
new file mode 100644
index 00000000..965f97cc
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820026.txt
@@ -0,0 +1,3 @@
+an old style street lamp post
+in the middle of some leafy vines
+on a wooden alley wall.
diff --git a/www/photo.causal.agency/2024-06-25/000099820029.txt b/www/photo.causal.agency/2024-06-25/000099820029.txt
new file mode 100644
index 00000000..9a29161d
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820029.txt
@@ -0,0 +1,3 @@
+a little lantern house thing
+hanging from a tree,
+viewed from the corner.
diff --git a/www/photo.causal.agency/2024-06-25/000099820033.txt b/www/photo.causal.agency/2024-06-25/000099820033.txt
new file mode 100644
index 00000000..5c591d15
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820033.txt
@@ -0,0 +1,3 @@
+some piece of broken mechanical equipment
+lying on the ground next to a tree
+among little plants.
diff --git a/www/photo.causal.agency/2024-06-25/000099820035.txt b/www/photo.causal.agency/2024-06-25/000099820035.txt
new file mode 100644
index 00000000..75ff71b5
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820035.txt
@@ -0,0 +1,7 @@
+a cat looking sleepy
+lying on a little bench
+with a blanket over it
+on someone's porch.
+behind it is a window
+with a cat flap
+and to the right is a bicycle.
diff --git a/www/photo.causal.agency/2024-06-25/000099820038.txt b/www/photo.causal.agency/2024-06-25/000099820038.txt
new file mode 100644
index 00000000..925e3597
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/000099820038.txt
@@ -0,0 +1,5 @@
+mechanical bits
+at the bottom corner
+of a big metal dumpster bin
+you use to dispose of
+construction detritus.
diff --git a/www/photo.causal.agency/2024-06-25/film b/www/photo.causal.agency/2024-06-25/film
new file mode 100644
index 00000000..919ded67
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/film
@@ -0,0 +1 @@
+Ilford HP5 Plus 400
diff --git a/www/photo.causal.agency/2024-06-25/lens b/www/photo.causal.agency/2024-06-25/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-06-25/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-07-01/000099800001.txt b/www/photo.causal.agency/2024-07-01/000099800001.txt
new file mode 100644
index 00000000..fe6ea42d
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800001.txt
@@ -0,0 +1,11 @@
+a floor of a building raised on stilts,
+though they aren't in frame.
+it's a beige plaster wall
+with a set of doors
+in the centre
+guarded by just a fence
+with no balcony.
+the doors are flanked
+by windows on either side.
+the doors and windows
+have oversized outlines in grey.
diff --git a/www/photo.causal.agency/2024-07-01/000099800002.txt b/www/photo.causal.agency/2024-07-01/000099800002.txt
new file mode 100644
index 00000000..3f06a708
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800002.txt
@@ -0,0 +1,4 @@
+a smashed glass bottle
+on the curb.
+there are dead leaves
+and a tissue mixed in there.
diff --git a/www/photo.causal.agency/2024-07-01/000099800007.txt b/www/photo.causal.agency/2024-07-01/000099800007.txt
new file mode 100644
index 00000000..955e3e2b
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800007.txt
@@ -0,0 +1,4 @@
+vines on a wooden lattice
+separating two white garage doors
+each with a row of windows
+behind grates in their top segments.
diff --git a/www/photo.causal.agency/2024-07-01/000099800008.txt b/www/photo.causal.agency/2024-07-01/000099800008.txt
new file mode 100644
index 00000000..01949d67
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800008.txt
@@ -0,0 +1,4 @@
+a green leafy plant
+on a dark red, almost brown wall.
+the paint of the wall is chipped.
+the tops of the leaves are directly in the sun.
diff --git a/www/photo.causal.agency/2024-07-01/000099800011.txt b/www/photo.causal.agency/2024-07-01/000099800011.txt
new file mode 100644
index 00000000..942d94fd
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800011.txt
@@ -0,0 +1,3 @@
+some kind of weird bushy thing
+on the end of a tree branch
+glowing in the sun.
diff --git a/www/photo.causal.agency/2024-07-01/000099800017.txt b/www/photo.causal.agency/2024-07-01/000099800017.txt
new file mode 100644
index 00000000..eac31685
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800017.txt
@@ -0,0 +1,2 @@
+the side of an old red convertible car.
+it seems to be decaying a little bit.
diff --git a/www/photo.causal.agency/2024-07-01/000099800020.txt b/www/photo.causal.agency/2024-07-01/000099800020.txt
new file mode 100644
index 00000000..0b09138f
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800020.txt
@@ -0,0 +1,7 @@
+the front of an old red pickup truck
+parked in an alley
+surrounded by overgrown plants
+indicating it has not moved in a long time.
+the spot on the front grill
+where the ford badge should be
+is empty.
diff --git a/www/photo.causal.agency/2024-07-01/000099800021.txt b/www/photo.causal.agency/2024-07-01/000099800021.txt
new file mode 100644
index 00000000..09e406bf
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/000099800021.txt
@@ -0,0 +1,4 @@
+a stripey cat sneaking
+in an alley in front of a wooden fence
+and behind a big blue hose
+on the ground.
diff --git a/www/photo.causal.agency/2024-07-01/film b/www/photo.causal.agency/2024-07-01/film
new file mode 100644
index 00000000..dcb63ffb
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/film
@@ -0,0 +1 @@
+Kodak Gold 200
diff --git a/www/photo.causal.agency/2024-07-01/lens b/www/photo.causal.agency/2024-07-01/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-01/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-07-03/000099800022.txt b/www/photo.causal.agency/2024-07-03/000099800022.txt
new file mode 100644
index 00000000..32311eec
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099800022.txt
@@ -0,0 +1,6 @@
+a large moss-covered rock
+with the sun hitting
+a surface near the middle.
+right in the bottom right
+corner beside the rock
+is an old discarded soda can.
diff --git a/www/photo.causal.agency/2024-07-03/000099800023.txt b/www/photo.causal.agency/2024-07-03/000099800023.txt
new file mode 100644
index 00000000..0fa3459e
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099800023.txt
@@ -0,0 +1,4 @@
+an old discarded soda can
+with a faded red label
+lying on a bed of dead leaves
+next to a large moss-covered rock.
diff --git a/www/photo.causal.agency/2024-07-03/000099800032.txt b/www/photo.causal.agency/2024-07-03/000099800032.txt
new file mode 100644
index 00000000..6c9606aa
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099800032.txt
@@ -0,0 +1,9 @@
+view of the richelieu river
+from one of the peaks of
+mont saint-hilaire.
+there is a bridge
+crossing the river
+and a surrounding town.
+the horizon is hazy
+fading into an overcast sky
+in the distance.
diff --git a/www/photo.causal.agency/2024-07-03/000099800036.txt b/www/photo.causal.agency/2024-07-03/000099800036.txt
new file mode 100644
index 00000000..1889fdc9
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099800036.txt
@@ -0,0 +1,3 @@
+another view of the richelieu river,
+looking further into the distance
+at mont saint-bruno.
diff --git a/www/photo.causal.agency/2024-07-03/000099810001.txt b/www/photo.causal.agency/2024-07-03/000099810001.txt
new file mode 100644
index 00000000..d4518651
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810001.txt
@@ -0,0 +1,4 @@
+a view of the richelieu river
+between some trees.
+the greens are much deeper
+on this film stock.
diff --git a/www/photo.causal.agency/2024-07-03/000099810002.txt b/www/photo.causal.agency/2024-07-03/000099810002.txt
new file mode 100644
index 00000000..4669d861
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810002.txt
@@ -0,0 +1,4 @@
+Ayla on a peak of mont saint-hilaire
+looking down at her phone.
+she's wearing a pink tshirt
+and a white ballcap.
diff --git a/www/photo.causal.agency/2024-07-03/000099810008.txt b/www/photo.causal.agency/2024-07-03/000099810008.txt
new file mode 100644
index 00000000..9ef302f8
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810008.txt
@@ -0,0 +1,3 @@
+a short wooden signpost
+without a sign on it,
+planted in a mound of rocks.
diff --git a/www/photo.causal.agency/2024-07-03/000099810013.txt b/www/photo.causal.agency/2024-07-03/000099810013.txt
new file mode 100644
index 00000000..39f75d2e
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810013.txt
@@ -0,0 +1,6 @@
+a view past the river
+of the town surrounding it
+and the farmland beyond.
+the leaves of a tree
+in the lower left
+are blowing hard in the wind.
diff --git a/www/photo.causal.agency/2024-07-03/000099810014.txt b/www/photo.causal.agency/2024-07-03/000099810014.txt
new file mode 100644
index 00000000..1a49f2ce
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810014.txt
@@ -0,0 +1,7 @@
+view of the road
+(and rail?)
+leading out of town,
+above a wooden sign post
+pointing left for "Accueil",
+which is like several kilometres
+away from this peak.
diff --git a/www/photo.causal.agency/2024-07-03/000099810017.txt b/www/photo.causal.agency/2024-07-03/000099810017.txt
new file mode 100644
index 00000000..c95c121e
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810017.txt
@@ -0,0 +1,6 @@
+view of the richelieu river
+snaking away into the distance
+from a rocky peak
+of mont saint-hilaire.
+a small wooden signpost
+is stuck into a rock.
diff --git a/www/photo.causal.agency/2024-07-03/000099810019.txt b/www/photo.causal.agency/2024-07-03/000099810019.txt
new file mode 100644
index 00000000..a2e47562
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810019.txt
@@ -0,0 +1,5 @@
+a view of the richelieu river
+to the north.
+the town on this side
+appears to have many cookie-cutter houses.
+there is farmland not far beyond.
diff --git a/www/photo.causal.agency/2024-07-03/000099810021.txt b/www/photo.causal.agency/2024-07-03/000099810021.txt
new file mode 100644
index 00000000..64537e52
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810021.txt
@@ -0,0 +1,4 @@
+a large bird of prey
+gliding across the horizon
+with the town below
+and the river to the left.
diff --git a/www/photo.causal.agency/2024-07-03/000099810022.txt b/www/photo.causal.agency/2024-07-03/000099810022.txt
new file mode 100644
index 00000000..2dbaabd3
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/000099810022.txt
@@ -0,0 +1,4 @@
+a view from one peak,
+across another covered in trees,
+to the river, town and farmland
+in the distance.
diff --git a/www/photo.causal.agency/2024-07-03/film b/www/photo.causal.agency/2024-07-03/film
new file mode 100644
index 00000000..eca5ad01
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/film
@@ -0,0 +1 @@
+Kodak Gold 200, Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-07-03/lens b/www/photo.causal.agency/2024-07-03/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-03/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-07-04/000099810029.txt b/www/photo.causal.agency/2024-07-04/000099810029.txt
new file mode 100644
index 00000000..d3201be9
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-04/000099810029.txt
@@ -0,0 +1,6 @@
+a cluster of small pink flowers
+on a bush.
+there are other clusters in the background.
+one is nearer to the camera
+but only some of its buds
+have started blooming.
diff --git a/www/photo.causal.agency/2024-07-04/000099810033.txt b/www/photo.causal.agency/2024-07-04/000099810033.txt
new file mode 100644
index 00000000..da44c8ce
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-04/000099810033.txt
@@ -0,0 +1,6 @@
+a brick house crowded by trees.
+the front face is painted a light blue.
+there's a tall narrow window
+above a garage door,
+and a balcony
+with some cloth draped over its railing.
diff --git a/www/photo.causal.agency/2024-07-04/000099810036.txt b/www/photo.causal.agency/2024-07-04/000099810036.txt
new file mode 100644
index 00000000..fa3bba11
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-04/000099810036.txt
@@ -0,0 +1,2 @@
+a standard issue red fire hydrant
+crowded by green leaves.
diff --git a/www/photo.causal.agency/2024-07-04/film b/www/photo.causal.agency/2024-07-04/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-04/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-07-04/lens b/www/photo.causal.agency/2024-07-04/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-04/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-07-06/000005110004.txt b/www/photo.causal.agency/2024-07-06/000005110004.txt
new file mode 100644
index 00000000..67518ba3
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/000005110004.txt
@@ -0,0 +1,8 @@
+view looking up
+at the corner of a weird bit
+of a house's balcony type thing.
+the top edge of the roof
+extends over the edge of the inset balcony.
+I have no idea how to explain it.
+there are trees around it
+and sky behind it.
diff --git a/www/photo.causal.agency/2024-07-06/000005110005.txt b/www/photo.causal.agency/2024-07-06/000005110005.txt
new file mode 100644
index 00000000..5ce7cd82
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/000005110005.txt
@@ -0,0 +1,5 @@
+two small shattered lightbulbs
+on a sidewalk.
+they appear to be actual bulbs
+surrounded by plastic,
+and it's the plastic that's shattered.
diff --git a/www/photo.causal.agency/2024-07-06/000005110012.txt b/www/photo.causal.agency/2024-07-06/000005110012.txt
new file mode 100644
index 00000000..89e6e8df
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/000005110012.txt
@@ -0,0 +1,3 @@
+the reflection of
+a big concrete block factory-turned-office building
+in a large puddle.
diff --git a/www/photo.causal.agency/2024-07-06/000005110013.txt b/www/photo.causal.agency/2024-07-06/000005110013.txt
new file mode 100644
index 00000000..75fc3284
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/000005110013.txt
@@ -0,0 +1,7 @@
+an unnecessarily large concrete block
+of a building
+that I'm pretty sure was once factories
+but is now office space.
+there are two sections about 11 storeys tall
+separated by a narrow section
+that is only 3.
diff --git a/www/photo.causal.agency/2024-07-06/000005110014.txt b/www/photo.causal.agency/2024-07-06/000005110014.txt
new file mode 100644
index 00000000..bf423e19
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/000005110014.txt
@@ -0,0 +1,3 @@
+a view close to the ground
+on some railroad tracks
+right before they go around a bend.
diff --git a/www/photo.causal.agency/2024-07-06/000005110017.txt b/www/photo.causal.agency/2024-07-06/000005110017.txt
new file mode 100644
index 00000000..ea58b0bb
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/000005110017.txt
@@ -0,0 +1,2 @@
+a broken wooden picture frame
+on a wet sidewalk
diff --git a/www/photo.causal.agency/2024-07-06/film b/www/photo.causal.agency/2024-07-06/film
new file mode 100644
index 00000000..919ded67
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/film
@@ -0,0 +1 @@
+Ilford HP5 Plus 400
diff --git a/www/photo.causal.agency/2024-07-06/lens b/www/photo.causal.agency/2024-07-06/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-06/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-07-09/000005110025.txt b/www/photo.causal.agency/2024-07-09/000005110025.txt
new file mode 100644
index 00000000..ecc57512
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110025.txt
@@ -0,0 +1,5 @@
+close up of a a flower
+with a bee on it.
+the bee is reaching down
+between the petals
+and you can see its fuzzy butt.
diff --git a/www/photo.causal.agency/2024-07-09/000005110026.txt b/www/photo.causal.agency/2024-07-09/000005110026.txt
new file mode 100644
index 00000000..fe3296d2
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110026.txt
@@ -0,0 +1,8 @@
+the top edge of
+the corner of a stone building
+covered in vines.
+there are two pillars
+going up towards the top.
+the left one is covered in vines
+and the right one is bare.
+between the pillars is the top of a window.
diff --git a/www/photo.causal.agency/2024-07-09/000005110028.txt b/www/photo.causal.agency/2024-07-09/000005110028.txt
new file mode 100644
index 00000000..1e808379
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110028.txt
@@ -0,0 +1,3 @@
+a small bird perched atop a roof peak,
+looking towards me.
+I believe this was a cardinal.
diff --git a/www/photo.causal.agency/2024-07-09/000005110029.txt b/www/photo.causal.agency/2024-07-09/000005110029.txt
new file mode 100644
index 00000000..f5d38a6b
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110029.txt
@@ -0,0 +1,9 @@
+the side of a brick building
+centred around the brick
+bearing the erection year.
+the raised portions of the 19
+have fallen off,
+and only the 08 is left.
+above this is the edge of the roof
+and below it are two ornamental bricks
+at the tops of windows.
diff --git a/www/photo.causal.agency/2024-07-09/000005110030.txt b/www/photo.causal.agency/2024-07-09/000005110030.txt
new file mode 100644
index 00000000..cff02d83
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110030.txt
@@ -0,0 +1,5 @@
+close up of a spiky ball flower.
+on the left a butterfly is perched on it,
+on the bottom right a bee.
+there is another spiky ball flower
+below the butterfly.
diff --git a/www/photo.causal.agency/2024-07-09/000005110033.txt b/www/photo.causal.agency/2024-07-09/000005110033.txt
new file mode 100644
index 00000000..688546f6
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110033.txt
@@ -0,0 +1,6 @@
+three vertically stacked power lines
+at a junction where two sets
+of three smaller cables
+go off in opposite directions.
+the dark lines contrast nicely
+against the lighter background.
diff --git a/www/photo.causal.agency/2024-07-09/000005110035.txt b/www/photo.causal.agency/2024-07-09/000005110035.txt
new file mode 100644
index 00000000..fb7226c6
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110035.txt
@@ -0,0 +1,6 @@
+a ladder leading to the top of a roof
+against the sky.
+the ladder is quite a bit taller
+than it needs to be
+so it ascends into the sky
+a little bit.
diff --git a/www/photo.causal.agency/2024-07-09/000005110036.txt b/www/photo.causal.agency/2024-07-09/000005110036.txt
new file mode 100644
index 00000000..d0628000
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/000005110036.txt
@@ -0,0 +1,8 @@
+the column of bricks
+that was once a chimney
+on the side of a triangular roofed house.
+the bricks are painted a light colour
+but it is peeling in many places.
+there is one of those wireframe
+rectangular sort of satellite dish things
+on the side of the column.
diff --git a/www/photo.causal.agency/2024-07-09/film b/www/photo.causal.agency/2024-07-09/film
new file mode 100644
index 00000000..919ded67
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/film
@@ -0,0 +1 @@
+Ilford HP5 Plus 400
diff --git a/www/photo.causal.agency/2024-07-09/lens b/www/photo.causal.agency/2024-07-09/lens
new file mode 100644
index 00000000..96b4d0a0
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-09/lens
@@ -0,0 +1 @@
+Osawa MC 70–210mm ƒ/4–5
diff --git a/www/photo.causal.agency/2024-07-14/000009180002.txt b/www/photo.causal.agency/2024-07-14/000009180002.txt
new file mode 100644
index 00000000..57ce6c98
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180002.txt
@@ -0,0 +1,3 @@
+a big red flower
+in the centre of the frame
+with a dark green blurred background.
diff --git a/www/photo.causal.agency/2024-07-14/000009180006.txt b/www/photo.causal.agency/2024-07-14/000009180006.txt
new file mode 100644
index 00000000..938ec690
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180006.txt
@@ -0,0 +1,10 @@
+a weird plant with
+like long stalks of I guess seeds
+with little crowns of white flowers on the ends.
+the depth of field is really shallow
+so they come in and out of focus
+from the blurred green background.
+in the centre there's a bee
+on one of the flowered ends
+but it's too close to the camera
+it's not in focus.
diff --git a/www/photo.causal.agency/2024-07-14/000009180010.txt b/www/photo.causal.agency/2024-07-14/000009180010.txt
new file mode 100644
index 00000000..f1e891de
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180010.txt
@@ -0,0 +1,8 @@
+two windows at the top of a plateau building.
+the base of the building is green brick
+and the top roof part is orange shingles
+that appear very shiny in this photo.
+the windows set into the shingled part
+have big flattened triangle
+thingies on top.
+made of wood, you know.
diff --git a/www/photo.causal.agency/2024-07-14/000009180014.txt b/www/photo.causal.agency/2024-07-14/000009180014.txt
new file mode 100644
index 00000000..bf98a26b
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180014.txt
@@ -0,0 +1,3 @@
+close up of an orange and white cat's head
+looking away from the camera
+on a blurred green background.
diff --git a/www/photo.causal.agency/2024-07-14/000009180020.txt b/www/photo.causal.agency/2024-07-14/000009180020.txt
new file mode 100644
index 00000000..1f3763ae
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180020.txt
@@ -0,0 +1,11 @@
+a flower cluster
+in the shape of a ball
+where all the tiny flowers
+come out of a centre point
+on long stems.
+the flowers themselves
+are either green or closed.
+the depth of field is shallow
+so there's a nice effect
+as the stems pop out
+at different angles to the lens.
diff --git a/www/photo.causal.agency/2024-07-14/000009180023.txt b/www/photo.causal.agency/2024-07-14/000009180023.txt
new file mode 100644
index 00000000..3cc28e4d
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180023.txt
@@ -0,0 +1,5 @@
+an array of small whitish flowers
+some of which are too close to the camera
+to be in focus
+and some of which are too far from the camera
+to be in focus.
diff --git a/www/photo.causal.agency/2024-07-14/000009180025.txt b/www/photo.causal.agency/2024-07-14/000009180025.txt
new file mode 100644
index 00000000..6f0e7e9c
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180025.txt
@@ -0,0 +1,6 @@
+a building extension
+whose exterior walls
+are made of severely rusting metal.
+the building is viewed from its corner,
+looking at its top
+against a blue sky.
diff --git a/www/photo.causal.agency/2024-07-14/000009180028.txt b/www/photo.causal.agency/2024-07-14/000009180028.txt
new file mode 100644
index 00000000..5dcc0fa4
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/000009180028.txt
@@ -0,0 +1,3 @@
+a painted spiral staircase
+enclosed on three sides
+by exterior walls.
diff --git a/www/photo.causal.agency/2024-07-14/film b/www/photo.causal.agency/2024-07-14/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-07-14/lens b/www/photo.causal.agency/2024-07-14/lens
new file mode 100644
index 00000000..96b4d0a0
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-14/lens
@@ -0,0 +1 @@
+Osawa MC 70–210mm ƒ/4–5
diff --git a/www/photo.causal.agency/2024-07-27/000025480003.txt b/www/photo.causal.agency/2024-07-27/000025480003.txt
new file mode 100644
index 00000000..159a8688
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-27/000025480003.txt
@@ -0,0 +1,5 @@
+geese on the water.
+there's a group of three in the foreground.
+two on the left have their heads underwater
+and the one on the right looks like it's about to stick its head under.
+there are a handful more in the background.
diff --git a/www/photo.causal.agency/2024-07-27/000025480009.txt b/www/photo.causal.agency/2024-07-27/000025480009.txt
new file mode 100644
index 00000000..53856b80
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-27/000025480009.txt
@@ -0,0 +1,2 @@
+a green buoy in the middle of the river.
+the far shore is rocky with some trees.
diff --git a/www/photo.causal.agency/2024-07-27/000025480010.txt b/www/photo.causal.agency/2024-07-27/000025480010.txt
new file mode 100644
index 00000000..8d46b7f5
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-27/000025480010.txt
@@ -0,0 +1,5 @@
+the jacques-cartier bridge
+viewed from a perpendicular angle,
+right at the middle of it.
+a roller coaster can be seen behind it on the right
+and a cargo boat on the left.
diff --git a/www/photo.causal.agency/2024-07-27/000025480012.txt b/www/photo.causal.agency/2024-07-27/000025480012.txt
new file mode 100644
index 00000000..34555365
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-27/000025480012.txt
@@ -0,0 +1,7 @@
+an outdoor electrical outlet
+mounted on a big piece of stone,
+nestled in a corner
+made by other big pieces of stone.
+there are pine needles and white fluff
+on the ground in front of it.
+its door has come off.
diff --git a/www/photo.causal.agency/2024-07-27/film b/www/photo.causal.agency/2024-07-27/film
new file mode 100644
index 00000000..97a445ae
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-27/film
@@ -0,0 +1 @@
+Shanghai Color Film 400
diff --git a/www/photo.causal.agency/2024-07-27/lens b/www/photo.causal.agency/2024-07-27/lens
new file mode 100644
index 00000000..96b4d0a0
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-27/lens
@@ -0,0 +1 @@
+Osawa MC 70–210mm ƒ/4–5
diff --git a/www/photo.causal.agency/2024-07-29/000025480014.txt b/www/photo.causal.agency/2024-07-29/000025480014.txt
new file mode 100644
index 00000000..7d3094e0
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480014.txt
@@ -0,0 +1,3 @@
+a green spiral metal staircase
+going up a brick wall
+absolutely covered in leafy vines.
diff --git a/www/photo.causal.agency/2024-07-29/000025480017.txt b/www/photo.causal.agency/2024-07-29/000025480017.txt
new file mode 100644
index 00000000..19137d80
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480017.txt
@@ -0,0 +1,5 @@
+the back or side of a building,
+probably a short office building,
+with columns of windows
+separated by uh,
+protruding bits of the building.
diff --git a/www/photo.causal.agency/2024-07-29/000025480018.txt b/www/photo.causal.agency/2024-07-29/000025480018.txt
new file mode 100644
index 00000000..2712fe2f
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480018.txt
@@ -0,0 +1,5 @@
+the top edge of a building,
+including power line pole
+on the roof,
+metal beam sticking out the side,
+and a little stone chimney.
diff --git a/www/photo.causal.agency/2024-07-29/000025480028.txt b/www/photo.causal.agency/2024-07-29/000025480028.txt
new file mode 100644
index 00000000..0a56a06c
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480028.txt
@@ -0,0 +1,11 @@
+a view all the way up the side
+of an old brick factory building,
+7 storeys tall.
+all of the windows on the far right
+have been filled in with cement.
+some of the other windows
+have been filled in with
+what looks like corrugated metal.
+some of the remaining windows
+are the original 6x3 pane
+and some are single pane.
diff --git a/www/photo.causal.agency/2024-07-29/000025480030.txt b/www/photo.causal.agency/2024-07-29/000025480030.txt
new file mode 100644
index 00000000..3ac51b0d
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480030.txt
@@ -0,0 +1,21 @@
+the intersection or interior corner
+of old brick factory buildings.
+we're sort of looking at a vertical W shape,
+with two buildings on either side
+at a right angle,
+and one corner peice of building
+jutting out between the other two.
+the old factory windows
+of these buildings
+are in various states of boarded up
+or filled in with concrete
+or left as-is.
+there are pipes and ducts and conduits
+crawling all over the buildings.
+the right side wall
+of the middle building piece
+is covered in leafy vines.
+the middle section
+is shorter than the others
+and light is coming over top of it
+hitting the leftmost building.
diff --git a/www/photo.causal.agency/2024-07-29/000025480033.txt b/www/photo.causal.agency/2024-07-29/000025480033.txt
new file mode 100644
index 00000000..41594319
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480033.txt
@@ -0,0 +1,7 @@
+detail of the centre corner piece of building
+from the previous photo,
+with pipes going up along
+the left building where it intersects
+with the middle building,
+and a conduit going across
+the top of where the vines reach.
diff --git a/www/photo.causal.agency/2024-07-29/000025480034.txt b/www/photo.causal.agency/2024-07-29/000025480034.txt
new file mode 100644
index 00000000..8a2c3227
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480034.txt
@@ -0,0 +1,8 @@
+part of an old factory building,
+a storey or two up.
+what used to be a window
+has been filled in with big grey stone bricks,
+but the metal cage over the outside
+has been left in place.
+a whole array of pipes climbs
+the building to the left.
diff --git a/www/photo.causal.agency/2024-07-29/000025480035.txt b/www/photo.causal.agency/2024-07-29/000025480035.txt
new file mode 100644
index 00000000..4ec13a5e
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480035.txt
@@ -0,0 +1,7 @@
+the intersection of some old brick factory buildings.
+windows are variously boarded up or filled in.
+one of the walls has leafy vines climbing up it,
+stopping at a conduit that's going across.
+a large duct goes up the building
+next to the vines.
+light is pouring over the top edge of the building.
diff --git a/www/photo.causal.agency/2024-07-29/000025480036.txt b/www/photo.causal.agency/2024-07-29/000025480036.txt
new file mode 100644
index 00000000..0554a5de
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/000025480036.txt
@@ -0,0 +1,15 @@
+the brick wall of an old factory building
+with sets of 6x4 pane windows,
+where it looks like the middle 4x2
+panes swivel open.
+a round duct or chimney
+has been installed
+in one of the lower windows
+and goes up the outside of the building.
+two of the other windows
+have been filled in,
+one with brick
+and one with metal.
+they both have vents embedded in them.
+an array of pipes climbs halfway up
+the far right edge of this wall.
diff --git a/www/photo.causal.agency/2024-07-29/film b/www/photo.causal.agency/2024-07-29/film
new file mode 100644
index 00000000..97a445ae
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/film
@@ -0,0 +1 @@
+Shanghai Color Film 400
diff --git a/www/photo.causal.agency/2024-07-29/lens b/www/photo.causal.agency/2024-07-29/lens
new file mode 100644
index 00000000..705b4e57
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-29/lens
@@ -0,0 +1 @@
+Yashica ML Zoom 28–85mm ƒ/3.5–4.5
diff --git a/www/photo.causal.agency/2024-07-30/000025490001.txt b/www/photo.causal.agency/2024-07-30/000025490001.txt
new file mode 100644
index 00000000..290ac209
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490001.txt
@@ -0,0 +1,2 @@
+two empty swings in a park.
+beyond there is a bench and a trash can.
diff --git a/www/photo.causal.agency/2024-07-30/000025490002.txt b/www/photo.causal.agency/2024-07-30/000025490002.txt
new file mode 100644
index 00000000..5554d178
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490002.txt
@@ -0,0 +1,4 @@
+some sort of small power station type building.
+its address is 4131,
+and there's a lamp above that number.
+to the right there's a fenced off area.
diff --git a/www/photo.causal.agency/2024-07-30/000025490003.txt b/www/photo.causal.agency/2024-07-30/000025490003.txt
new file mode 100644
index 00000000..4b2573af
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490003.txt
@@ -0,0 +1,2 @@
+some round white paper lantern type things
+hanging under an elevated deck.
diff --git a/www/photo.causal.agency/2024-07-30/000025490004.txt b/www/photo.causal.agency/2024-07-30/000025490004.txt
new file mode 100644
index 00000000..81409be3
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490004.txt
@@ -0,0 +1,6 @@
+two wooden construction barriers at angles to each other
+at the edge of a park.
+neither are supported on both sides.
+one is coming towards the camera,
+the other is going across.
+it says ABF on it.
diff --git a/www/photo.causal.agency/2024-07-30/000025490009.txt b/www/photo.causal.agency/2024-07-30/000025490009.txt
new file mode 100644
index 00000000..6e38b667
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490009.txt
@@ -0,0 +1,4 @@
+a series of 4 power line poles
+in close proximity
+against a grey sky
+in front of a completely shadowed building.
diff --git a/www/photo.causal.agency/2024-07-30/000025490010.txt b/www/photo.causal.agency/2024-07-30/000025490010.txt
new file mode 100644
index 00000000..75853ca8
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490010.txt
@@ -0,0 +1,3 @@
+an empty field with some sort of small tripod structure
+in the middle.
+beyond it are condo buildings.
diff --git a/www/photo.causal.agency/2024-07-30/000025490012.txt b/www/photo.causal.agency/2024-07-30/000025490012.txt
new file mode 100644
index 00000000..6d3bc3c4
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490012.txt
@@ -0,0 +1,5 @@
+a public pool in a park
+at night illuminated by flood light above.
+in the centre of the frame
+are two diving boards side by side
+with metal railings.
diff --git a/www/photo.causal.agency/2024-07-30/000025490014.txt b/www/photo.causal.agency/2024-07-30/000025490014.txt
new file mode 100644
index 00000000..a85000f9
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/000025490014.txt
@@ -0,0 +1,5 @@
+a blinking red traffic light suspended above an intersection.
+it's completely dark
+except for the traffic light
+and some other source in the bottom left.
+the shape of a building and tree can be made out.
diff --git a/www/photo.causal.agency/2024-07-30/film b/www/photo.causal.agency/2024-07-30/film
new file mode 100644
index 00000000..919ded67
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/film
@@ -0,0 +1 @@
+Ilford HP5 Plus 400
diff --git a/www/photo.causal.agency/2024-07-30/lens b/www/photo.causal.agency/2024-07-30/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-07-30/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-08-02/000025490019.txt b/www/photo.causal.agency/2024-08-02/000025490019.txt
new file mode 100644
index 00000000..b8e3a89f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490019.txt
@@ -0,0 +1,5 @@
+close up of a bundle of small pipes
+that come up out of the ground
+around person height
+and curve downwards at the top,
+with the ends covered by a rough metal mesh.
diff --git a/www/photo.causal.agency/2024-08-02/000025490026.txt b/www/photo.causal.agency/2024-08-02/000025490026.txt
new file mode 100644
index 00000000..dd5049e7
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490026.txt
@@ -0,0 +1,5 @@
+the side of a concrete building
+with an intricate pattern
+of concrete and narrow windows.
+the windows are reflecting a light sky.
+good contrast and shadows here.
diff --git a/www/photo.causal.agency/2024-08-02/000025490027.txt b/www/photo.causal.agency/2024-08-02/000025490027.txt
new file mode 100644
index 00000000..15d6847a
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490027.txt
@@ -0,0 +1,6 @@
+a wider view of
+the side of a concrete building
+with an intricate pattern
+of concrete and narrow windows.
+the windows are reflecting a light sky.
+good contrast and shadows here.
diff --git a/www/photo.causal.agency/2024-08-02/000025490029.txt b/www/photo.causal.agency/2024-08-02/000025490029.txt
new file mode 100644
index 00000000..f9f86887
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490029.txt
@@ -0,0 +1,6 @@
+the back of a haphazard
+building extension
+with walls of corrugated metal,
+vines growing lazily all over it.
+the right side appears to
+be covered only by a canvas roof.
diff --git a/www/photo.causal.agency/2024-08-02/000025490030.txt b/www/photo.causal.agency/2024-08-02/000025490030.txt
new file mode 100644
index 00000000..eb7a4b13
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490030.txt
@@ -0,0 +1,5 @@
+a metal cylinder
+with a thick cable going through it
+suspended against a brick wall
+by a smaller steel cable
+bolted into the wall.
diff --git a/www/photo.causal.agency/2024-08-02/000025490031.txt b/www/photo.causal.agency/2024-08-02/000025490031.txt
new file mode 100644
index 00000000..3a6e576e
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490031.txt
@@ -0,0 +1,4 @@
+the shallow sloped roof
+of a house with a single window
+protruding from it on the right.
+trees beyond the roof.
diff --git a/www/photo.causal.agency/2024-08-02/000025490035.txt b/www/photo.causal.agency/2024-08-02/000025490035.txt
new file mode 100644
index 00000000..60ac4e32
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490035.txt
@@ -0,0 +1,7 @@
+the side of a brick building
+that is featureless until a couple storeys up
+where there are squares of glass cube grids
+with small actuall windows
+embedded in them off-centre.
+the windows are separated by columns of bricks
+that go down the outside of the building.
diff --git a/www/photo.causal.agency/2024-08-02/000025490036.txt b/www/photo.causal.agency/2024-08-02/000025490036.txt
new file mode 100644
index 00000000..4de137fb
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/000025490036.txt
@@ -0,0 +1,11 @@
+the cube.
+the rectangle.
+it's a modern part of a building
+that's been added onto over time.
+and it's just a big rectangle
+with like a dev texture on it
+and some weirdly placed windows.
+we're looking up at it
+from an angle
+and the sun is hitting the top corner of it.
+it looks imposing.
diff --git a/www/photo.causal.agency/2024-08-02/film b/www/photo.causal.agency/2024-08-02/film
new file mode 100644
index 00000000..919ded67
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/film
@@ -0,0 +1 @@
+Ilford HP5 Plus 400
diff --git a/www/photo.causal.agency/2024-08-02/lens b/www/photo.causal.agency/2024-08-02/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-02/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-08-10/000031420002.txt b/www/photo.causal.agency/2024-08-10/000031420002.txt
new file mode 100644
index 00000000..e9eac877
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420002.txt
@@ -0,0 +1,5 @@
+close up of a bundle of small pipes
+that come up out of the ground around person height
+and curve downwards at the top,
+with the ends covered by a rough metal mesh.
+they're sort of pale greenish coloured.
diff --git a/www/photo.causal.agency/2024-08-10/000031420005.txt b/www/photo.causal.agency/2024-08-10/000031420005.txt
new file mode 100644
index 00000000..dbc7c12a
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420005.txt
@@ -0,0 +1,4 @@
+a big bush of yellow flowers
+with flat petals that don't touch
+and big brown balls in the centre.
+they're glowing in the sunlight.
diff --git a/www/photo.causal.agency/2024-08-10/000031420007.txt b/www/photo.causal.agency/2024-08-10/000031420007.txt
new file mode 100644
index 00000000..6138ee21
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420007.txt
@@ -0,0 +1,3 @@
+one big flower with white petals
+that are deep red only right near the centre
+and a long plant reproductive bit.
diff --git a/www/photo.causal.agency/2024-08-10/000031420011.txt b/www/photo.causal.agency/2024-08-10/000031420011.txt
new file mode 100644
index 00000000..4dcc7c39
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420011.txt
@@ -0,0 +1,2 @@
+a cat lying down in an alley next to a little ball,
+looking at the camera.
diff --git a/www/photo.causal.agency/2024-08-10/000031420012.txt b/www/photo.causal.agency/2024-08-10/000031420012.txt
new file mode 100644
index 00000000..3d0b928c
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420012.txt
@@ -0,0 +1,4 @@
+close up of a cat in an alley
+with its eyes closed.
+it's lying next to a small ball.
+it has thumbs!
diff --git a/www/photo.causal.agency/2024-08-10/000031420015.txt b/www/photo.causal.agency/2024-08-10/000031420015.txt
new file mode 100644
index 00000000..7c116097
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420015.txt
@@ -0,0 +1,4 @@
+the top of a discarded hot water tank
+with two severed pipes coming out.
+the top appears green,
+though it may have been blue.
diff --git a/www/photo.causal.agency/2024-08-10/000031420016.txt b/www/photo.causal.agency/2024-08-10/000031420016.txt
new file mode 100644
index 00000000..ea0af1e7
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420016.txt
@@ -0,0 +1,8 @@
+what is perhaps a planter
+among overgrowing plants,
+with two little wagon wheels
+seemingly broken off.
+one is leaning against the near side
+of the planter
+and the other is flat on the ground
+half under it.
diff --git a/www/photo.causal.agency/2024-08-10/000031420020.txt b/www/photo.causal.agency/2024-08-10/000031420020.txt
new file mode 100644
index 00000000..8ce4c5c1
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420020.txt
@@ -0,0 +1,2 @@
+power lines atop a wooden pole with 3 drums
+against a blue sky with white clouds.
diff --git a/www/photo.causal.agency/2024-08-10/000031420024.txt b/www/photo.causal.agency/2024-08-10/000031420024.txt
new file mode 100644
index 00000000..6d4ec555
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420024.txt
@@ -0,0 +1,3 @@
+a street lamp in an alley
+under the shade of a tree
+with two large spherical lamps.
diff --git a/www/photo.causal.agency/2024-08-10/000031420026.txt b/www/photo.causal.agency/2024-08-10/000031420026.txt
new file mode 100644
index 00000000..77297a74
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420026.txt
@@ -0,0 +1,3 @@
+a big ball of clustered tiny white flowers
+glowing in the sun
+on a bright blue sky.
diff --git a/www/photo.causal.agency/2024-08-10/000031420027.txt b/www/photo.causal.agency/2024-08-10/000031420027.txt
new file mode 100644
index 00000000..d31920e8
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420027.txt
@@ -0,0 +1,8 @@
+the side of a weird old presumably european tiny car
+that's been rotting in an alley for who knows how long.
+the car is painted black
+and there's a bunch of graffiti in white
+on the door and back side as well as the window.
+on the door next to the handle there's a stenciled "GREMA".
+the car is in worse shape
+than the last time I photographed it.
diff --git a/www/photo.causal.agency/2024-08-10/000031420028.txt b/www/photo.causal.agency/2024-08-10/000031420028.txt
new file mode 100644
index 00000000..e4cbd11f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420028.txt
@@ -0,0 +1,2 @@
+the steering wheel of an old presumably european car
+that has been left to rot in an alley.
diff --git a/www/photo.causal.agency/2024-08-10/000031420029.txt b/www/photo.causal.agency/2024-08-10/000031420029.txt
new file mode 100644
index 00000000..ea3361fb
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420029.txt
@@ -0,0 +1,3 @@
+a discarded bicycle tire
+in front of a mound of dirt and dead leaves
+in an alley.
diff --git a/www/photo.causal.agency/2024-08-10/000031420034.txt b/www/photo.causal.agency/2024-08-10/000031420034.txt
new file mode 100644
index 00000000..542924f3
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/000031420034.txt
@@ -0,0 +1,4 @@
+the top halves of some classic plateau rowhouses
+against a light blue sky with some clouds.
+the top windows are painted in a sequence of
+dark purple, orange, dark green, some kind of red.
diff --git a/www/photo.causal.agency/2024-08-10/body b/www/photo.causal.agency/2024-08-10/body
new file mode 100644
index 00000000..1828b2a2
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/body
@@ -0,0 +1 @@
+Zenit-122
diff --git a/www/photo.causal.agency/2024-08-10/film b/www/photo.causal.agency/2024-08-10/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-08-10/lens b/www/photo.causal.agency/2024-08-10/lens
new file mode 100644
index 00000000..dcd0812c
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-10/lens
@@ -0,0 +1 @@
+Helios-44M-5 58mm ƒ/2
diff --git a/www/photo.causal.agency/2024-08-22/000044750004.txt b/www/photo.causal.agency/2024-08-22/000044750004.txt
new file mode 100644
index 00000000..a6d758bd
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750004.txt
@@ -0,0 +1,2 @@
+a broken and fallen limb of a tree
+laying in a puddle in an alley.
diff --git a/www/photo.causal.agency/2024-08-22/000044750007.txt b/www/photo.causal.agency/2024-08-22/000044750007.txt
new file mode 100644
index 00000000..faf48f72
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750007.txt
@@ -0,0 +1,7 @@
+some kind of motor
+attached to some kind of machinery.
+it looks like a cable runs
+from a box on its sidee
+to another box not far
+with what looks like
+an ordinary light switch on it.
diff --git a/www/photo.causal.agency/2024-08-22/000044750008.txt b/www/photo.causal.agency/2024-08-22/000044750008.txt
new file mode 100644
index 00000000..1475b9e1
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750008.txt
@@ -0,0 +1,3 @@
+wrought iron fence detail.
+it's got swirly bits
+and squiggly pointy bits.
diff --git a/www/photo.causal.agency/2024-08-22/000044750009.txt b/www/photo.causal.agency/2024-08-22/000044750009.txt
new file mode 100644
index 00000000..a8c887cc
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750009.txt
@@ -0,0 +1,2 @@
+wider view of wrought iron fence
+showing two instances of its repeated pattern.
diff --git a/www/photo.causal.agency/2024-08-22/000044750010.txt b/www/photo.causal.agency/2024-08-22/000044750010.txt
new file mode 100644
index 00000000..8e275e06
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750010.txt
@@ -0,0 +1,3 @@
+a bike locked to a fence
+being overgrown by bushes
+and weeds and other plants.
diff --git a/www/photo.causal.agency/2024-08-22/000044750013.txt b/www/photo.causal.agency/2024-08-22/000044750013.txt
new file mode 100644
index 00000000..d89c3ac1
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750013.txt
@@ -0,0 +1,5 @@
+a bee sitting on a flower
+that has thin sort of curled up petals
+spaced far apart.
+sort of looks like the bee
+is humping the middle of the flower.
diff --git a/www/photo.causal.agency/2024-08-22/000044750014.txt b/www/photo.causal.agency/2024-08-22/000044750014.txt
new file mode 100644
index 00000000..0e591c1f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750014.txt
@@ -0,0 +1,8 @@
+a metal frame structure
+in the shape of half a cyllinder
+suspended,
+presumably over a walkway,
+on square concrete pillars.
+the pillars have three notches
+in them near the top.
+this is just outside a large stone building.
diff --git a/www/photo.causal.agency/2024-08-22/000044750016.txt b/www/photo.causal.agency/2024-08-22/000044750016.txt
new file mode 100644
index 00000000..ef9a68a3
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750016.txt
@@ -0,0 +1,7 @@
+the top of a large building
+with a pointed roof.
+some of the windows are intact
+while some have beams of wood
+across them on the outside
+seemingly holding boards of wood
+against the insides?
diff --git a/www/photo.causal.agency/2024-08-22/000044750024.txt b/www/photo.causal.agency/2024-08-22/000044750024.txt
new file mode 100644
index 00000000..b3c14768
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750024.txt
@@ -0,0 +1,6 @@
+a single cable,
+probably telephone,
+suspended by a pole
+in an upside-down L shape
+with a truss between
+the two pieces.
diff --git a/www/photo.causal.agency/2024-08-22/000044750027.txt b/www/photo.causal.agency/2024-08-22/000044750027.txt
new file mode 100644
index 00000000..3c614db2
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750027.txt
@@ -0,0 +1,5 @@
+a weird cube of building
+covered in a metal diamond tiling pattern
+with one wide window in the side
+and some cables under tension
+going down it.
diff --git a/www/photo.causal.agency/2024-08-22/000044750028.txt b/www/photo.causal.agency/2024-08-22/000044750028.txt
new file mode 100644
index 00000000..f6998321
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/000044750028.txt
@@ -0,0 +1,3 @@
+a row of back to back park benches
+among trees continuing
+into the distance away to the right.
diff --git a/www/photo.causal.agency/2024-08-22/body b/www/photo.causal.agency/2024-08-22/body
new file mode 100644
index 00000000..1828b2a2
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/body
@@ -0,0 +1 @@
+Zenit-122
diff --git a/www/photo.causal.agency/2024-08-22/film b/www/photo.causal.agency/2024-08-22/film
new file mode 100644
index 00000000..919ded67
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/film
@@ -0,0 +1 @@
+Ilford HP5 Plus 400
diff --git a/www/photo.causal.agency/2024-08-22/lens b/www/photo.causal.agency/2024-08-22/lens
new file mode 100644
index 00000000..dcd0812c
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-22/lens
@@ -0,0 +1 @@
+Helios-44M-5 58mm ƒ/2
diff --git a/www/photo.causal.agency/2024-08-23/000044740001.txt b/www/photo.causal.agency/2024-08-23/000044740001.txt
new file mode 100644
index 00000000..dcc7e42f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740001.txt
@@ -0,0 +1,8 @@
+an old-style metal lamp post
+on a solid wooden fence
+with vines growing over it.
+the left side of the frame
+and the bottom and top edges
+have red light bleeding into them
+from the film being exposed
+during loading.
diff --git a/www/photo.causal.agency/2024-08-23/000044740002.txt b/www/photo.causal.agency/2024-08-23/000044740002.txt
new file mode 100644
index 00000000..821c0b5b
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740002.txt
@@ -0,0 +1,5 @@
+a view down an alley
+past a tree with hanging leaves.
+bright sunlight is
+coming through a branch
+off the alley to the left.
diff --git a/www/photo.causal.agency/2024-08-23/000044740010.txt b/www/photo.causal.agency/2024-08-23/000044740010.txt
new file mode 100644
index 00000000..428ffe8f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740010.txt
@@ -0,0 +1,5 @@
+close up of a cluster
+of some kind of berries
+on a plant with nice green leaves.
+the stems appear red
+and the berries a dark blue.
diff --git a/www/photo.causal.agency/2024-08-23/000044740014.txt b/www/photo.causal.agency/2024-08-23/000044740014.txt
new file mode 100644
index 00000000..f04e5615
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740014.txt
@@ -0,0 +1,4 @@
+a big tall tree
+with branches that
+all point very upwards
+rather than outwards.
diff --git a/www/photo.causal.agency/2024-08-23/000044740017.txt b/www/photo.causal.agency/2024-08-23/000044740017.txt
new file mode 100644
index 00000000..ac8e4ba9
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740017.txt
@@ -0,0 +1,2 @@
+the top half of a big tree
+with many branching thick limbs.
diff --git a/www/photo.causal.agency/2024-08-23/000044740021.txt b/www/photo.causal.agency/2024-08-23/000044740021.txt
new file mode 100644
index 00000000..6ee78b65
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740021.txt
@@ -0,0 +1,5 @@
+view up at a huge old stone building
+with lots of 3D shape going on
+and lots of windows.
+past it is a blue sky
+with a big white fluffy cloud.
diff --git a/www/photo.causal.agency/2024-08-23/000044740024.txt b/www/photo.causal.agency/2024-08-23/000044740024.txt
new file mode 100644
index 00000000..f344f290
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740024.txt
@@ -0,0 +1,8 @@
+a completely empty bit of
+road or parking lot
+surrounded by trees,
+curving away and downward in the distance.
+on one side,
+behind construction fences,
+there's a tall street light
+with a blue P-5 sign attached.
diff --git a/www/photo.causal.agency/2024-08-23/000044740030.txt b/www/photo.causal.agency/2024-08-23/000044740030.txt
new file mode 100644
index 00000000..42d3ef1a
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740030.txt
@@ -0,0 +1,8 @@
+a wide set of concrete stairs
+divided by 4 sets of white metal railings
+ascending out into the sun
+from under a low concrete ceiling
+with a large square grid pattern.
+the ceiling is being lit
+by a sort of bluish-green light
+from behind.
diff --git a/www/photo.causal.agency/2024-08-23/000044740031.txt b/www/photo.causal.agency/2024-08-23/000044740031.txt
new file mode 100644
index 00000000..e566e86f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740031.txt
@@ -0,0 +1,4 @@
+a tall brutalist-ish apartment building
+on a mostly clear blue sky,
+with one white cloud in the bottom left.
+the building appears orange.
diff --git a/www/photo.causal.agency/2024-08-23/000044740033.txt b/www/photo.causal.agency/2024-08-23/000044740033.txt
new file mode 100644
index 00000000..44d1d1f5
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740033.txt
@@ -0,0 +1,6 @@
+the back of an old brick building
+that is probably being renovated.
+the ground is descending
+behind the building as if to underground parking,
+and there is a space for a door
+that is blocked with plywood.
diff --git a/www/photo.causal.agency/2024-08-23/000044740034.txt b/www/photo.causal.agency/2024-08-23/000044740034.txt
new file mode 100644
index 00000000..5492db03
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740034.txt
@@ -0,0 +1,6 @@
+looking up at an old red brick building
+from the ground.
+there are three rows of windows.
+there are also two doors
+with no handles and little square windows
+that would open onto nothing.
diff --git a/www/photo.causal.agency/2024-08-23/000044740035.txt b/www/photo.causal.agency/2024-08-23/000044740035.txt
new file mode 100644
index 00000000..3cf7a14f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740035.txt
@@ -0,0 +1,4 @@
+a pile of palettes stacked with slabs of stone
+sitting at the side of a brick building.
+based on how plants are growing around them,
+they haven't been touched in a while.
diff --git a/www/photo.causal.agency/2024-08-23/000044740036.txt b/www/photo.causal.agency/2024-08-23/000044740036.txt
new file mode 100644
index 00000000..c87ba240
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/000044740036.txt
@@ -0,0 +1,14 @@
+the back of a very strange
+residential building
+that's clearly been built onto.
+on the right is a regular red wooden door.
+on the left is a painted brown metal door
+with a circular window in it
+like a porthole.
+this is at the bottom of a metal column,
+presumably containing stairs,
+with one more porthole
+not far above the door.
+slid right between this weird extension
+and the side of the adjacent building
+is a very tall ladder.
diff --git a/www/photo.causal.agency/2024-08-23/body b/www/photo.causal.agency/2024-08-23/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-08-23/film b/www/photo.causal.agency/2024-08-23/film
new file mode 100644
index 00000000..2340483a
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/film
@@ -0,0 +1 @@
+Film Washi “X” 100
diff --git a/www/photo.causal.agency/2024-08-23/lens b/www/photo.causal.agency/2024-08-23/lens
new file mode 100644
index 00000000..465336d3
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-23/lens
@@ -0,0 +1 @@
+Makinon 28mm ƒ/2.8
diff --git a/www/photo.causal.agency/2024-08-24/000044730001.txt b/www/photo.causal.agency/2024-08-24/000044730001.txt
new file mode 100644
index 00000000..9481f22a
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730001.txt
@@ -0,0 +1,6 @@
+overhead lines for electric trains
+silhouetted against a blue sky.
+there's a train partially visible
+behind a concrete barrier.
+there's a pentagonal lens flare
+in the sky.
diff --git a/www/photo.causal.agency/2024-08-24/000044730002.txt b/www/photo.causal.agency/2024-08-24/000044730002.txt
new file mode 100644
index 00000000..c2290e3c
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730002.txt
@@ -0,0 +1,4 @@
+overhead lines for electric trains
+silhouetted against a blue sky
+with sparse clouds
+as a train goes past.
diff --git a/www/photo.causal.agency/2024-08-24/000044730004.txt b/www/photo.causal.agency/2024-08-24/000044730004.txt
new file mode 100644
index 00000000..5874fc87
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730004.txt
@@ -0,0 +1,5 @@
+a vast and empty parking lot
+under a blue sky with clouds in the distance.
+the parking lot extends at an angle
+away from a crosswalk in the foreground.
+behind the lot is a large shed.
diff --git a/www/photo.causal.agency/2024-08-24/000044730008.txt b/www/photo.causal.agency/2024-08-24/000044730008.txt
new file mode 100644
index 00000000..86ac6f65
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730008.txt
@@ -0,0 +1,6 @@
+a vast and empty parking lot
+under a blue sky fading into clouds.
+we are looking down a line of crosswalks
+that cross the lot.
+there are rows of young trees
+and lots of signs on metal poles.
diff --git a/www/photo.causal.agency/2024-08-24/000044730012.txt b/www/photo.causal.agency/2024-08-24/000044730012.txt
new file mode 100644
index 00000000..6311d731
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730012.txt
@@ -0,0 +1,3 @@
+some sort of device atop
+overhead lines for electric trains
+against a grey-blue sky.
diff --git a/www/photo.causal.agency/2024-08-24/000044730014.txt b/www/photo.causal.agency/2024-08-24/000044730014.txt
new file mode 100644
index 00000000..96e5e4dd
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730014.txt
@@ -0,0 +1,3 @@
+train tracks with overhead lines
+inside a fenced area.
+there are three parallel tracks.
diff --git a/www/photo.causal.agency/2024-08-24/000044730018.txt b/www/photo.causal.agency/2024-08-24/000044730018.txt
new file mode 100644
index 00000000..ae0ea59d
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730018.txt
@@ -0,0 +1,4 @@
+the wall of the base under a track,
+close at the left side of the frame
+and quickly stretching into the distance
+to the right.
diff --git a/www/photo.causal.agency/2024-08-24/000044730026.txt b/www/photo.causal.agency/2024-08-24/000044730026.txt
new file mode 100644
index 00000000..d646f8e5
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730026.txt
@@ -0,0 +1,8 @@
+the inside of a train station,
+with walls of orange-brown tile.
+there is a stairway leading up to the left,
+and one in shadow at the end of a short tunnel
+to the right.
+in the centre is a green sign
+pointing up the left stairs towards
+quai 1 and quai 3.
diff --git a/www/photo.causal.agency/2024-08-24/000044730028.txt b/www/photo.causal.agency/2024-08-24/000044730028.txt
new file mode 100644
index 00000000..3978d978
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730028.txt
@@ -0,0 +1,2 @@
+the tops of grass that has grown untended
+and has produced seeds and gone yellow/brown.
diff --git a/www/photo.causal.agency/2024-08-24/000044730029.txt b/www/photo.causal.agency/2024-08-24/000044730029.txt
new file mode 100644
index 00000000..52d3c975
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730029.txt
@@ -0,0 +1,2 @@
+a short set of curved wooden steps
+surrounded by leaves.
diff --git a/www/photo.causal.agency/2024-08-24/000044730030.txt b/www/photo.causal.agency/2024-08-24/000044730030.txt
new file mode 100644
index 00000000..de6ef2ff
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730030.txt
@@ -0,0 +1 @@
+close up of a cluster of little pink flowers.
diff --git a/www/photo.causal.agency/2024-08-24/000044730035.txt b/www/photo.causal.agency/2024-08-24/000044730035.txt
new file mode 100644
index 00000000..70b7e7ef
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/000044730035.txt
@@ -0,0 +1,4 @@
+an orange and white cat sitting in an alley
+looking off to the left.
+it's got a collar on
+with a little heard shaped tag on it.
diff --git a/www/photo.causal.agency/2024-08-24/body b/www/photo.causal.agency/2024-08-24/body
new file mode 100644
index 00000000..1828b2a2
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/body
@@ -0,0 +1 @@
+Zenit-122
diff --git a/www/photo.causal.agency/2024-08-24/film b/www/photo.causal.agency/2024-08-24/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-08-24/lens b/www/photo.causal.agency/2024-08-24/lens
new file mode 100644
index 00000000..19fafffb
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-24/lens
@@ -0,0 +1 @@
+Takumar 35mm ƒ/3.5, Helios-44M-5 58mm ƒ/2
diff --git a/www/photo.causal.agency/2024-08-29/000054970002.txt b/www/photo.causal.agency/2024-08-29/000054970002.txt
new file mode 100644
index 00000000..e58bb3c3
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-29/000054970002.txt
@@ -0,0 +1,3 @@
+reflection of trees and sky
+in water with ripples
+at early evening.
diff --git a/www/photo.causal.agency/2024-08-29/000054970004.txt b/www/photo.causal.agency/2024-08-29/000054970004.txt
new file mode 100644
index 00000000..b8ca6fc6
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-29/000054970004.txt
@@ -0,0 +1,5 @@
+rough concrete blocks
+stacked 3 by 3 except
+the top right one is missing.
+they're heavily weathered
+and have trees overhanging them.
diff --git a/www/photo.causal.agency/2024-08-29/body b/www/photo.causal.agency/2024-08-29/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-29/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-08-29/film b/www/photo.causal.agency/2024-08-29/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-29/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-08-29/lens b/www/photo.causal.agency/2024-08-29/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-29/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-09-02/000054970017.txt b/www/photo.causal.agency/2024-09-02/000054970017.txt
new file mode 100644
index 00000000..a90825a9
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/000054970017.txt
@@ -0,0 +1,11 @@
+a block of windows in a school building,
+viewed from a slight angle.
+the wall of the building is beige brick
+and the block of windows
+is bordered by grey stone.
+there are two rows of windows,
+and below each row are panels that appear brown,
+though they're orange in person.
+the top row of windows
+is reflecting some blue sky and clouds,
+while the bottom row is reflecting only cloud.
diff --git a/www/photo.causal.agency/2024-09-02/000054970018.txt b/www/photo.causal.agency/2024-09-02/000054970018.txt
new file mode 100644
index 00000000..db65ac6c
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/000054970018.txt
@@ -0,0 +1,7 @@
+a row of three benches on the front lawn of a school building.
+each bench is separated by bushes and trees.
+they're made up of planks of wood painted blue
+bolted to concrete supports.
+the school building behind them is beige brick
+and there are window AC units installed
+in each window of the second floor.
diff --git a/www/photo.causal.agency/2024-09-02/000054970019.txt b/www/photo.causal.agency/2024-09-02/000054970019.txt
new file mode 100644
index 00000000..18b9c733
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/000054970019.txt
@@ -0,0 +1,6 @@
+numerous stacks of wooden picnic tables
+on a lawn of grass in front of some trees.
+most of the stacks are piled three high,
+some four.
+the light coming through the branches and leaves
+of the trees in the background is glowing gold.
diff --git a/www/photo.causal.agency/2024-09-02/000054970021.txt b/www/photo.causal.agency/2024-09-02/000054970021.txt
new file mode 100644
index 00000000..2aac2c6f
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/000054970021.txt
@@ -0,0 +1,11 @@
+fancy windows on the side of a school building.
+it's a repeating pattern of three windows
+in the middle of a house-shaped design
+of yellow panels on the second floor.
+the middle windows are higher than the other two.
+the triangle at the top of the window design
+is followed by the profile of the roof.
+below that, separated by a row of even short windows,
+are red panels.
+the upper windows are reflecting blue sky and clouds,
+while the lower red panels are reflecting trees and clouds.
diff --git a/www/photo.causal.agency/2024-09-02/000054970022.txt b/www/photo.causal.agency/2024-09-02/000054970022.txt
new file mode 100644
index 00000000..df959a2c
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/000054970022.txt
@@ -0,0 +1,3 @@
+a light brown or beige brick school building
+with its rows of windows.
+the trim around the windows is sort of red-brown.
diff --git a/www/photo.causal.agency/2024-09-02/000054970023.txt b/www/photo.causal.agency/2024-09-02/000054970023.txt
new file mode 100644
index 00000000..976a4054
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/000054970023.txt
@@ -0,0 +1,3 @@
+a haphazard pile of broken and discarded park benches.
+they're nice ones made of wooden slats and black metal supports.
+some are nice warm brown and others are more grey.
diff --git a/www/photo.causal.agency/2024-09-02/000054970029.txt b/www/photo.causal.agency/2024-09-02/000054970029.txt
new file mode 100644
index 00000000..53907b76
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/000054970029.txt
@@ -0,0 +1,6 @@
+the wall of some kind of concrete structure
+surrounding a big white metal tank.
+I think the wall is actually metal,
+but the outline of the structure is concrete.
+it's got a lot of interesting marks and texture on it.
+it's very hard to describe.
diff --git a/www/photo.causal.agency/2024-09-02/body b/www/photo.causal.agency/2024-09-02/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-09-02/film b/www/photo.causal.agency/2024-09-02/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-09-02/lens b/www/photo.causal.agency/2024-09-02/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-02/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-09-05/06124000003.txt b/www/photo.causal.agency/2024-09-05/06124000003.txt
new file mode 100644
index 00000000..7b3b59e9
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000003.txt
@@ -0,0 +1,6 @@
+looking up at the corner of a grey office building
+of at least 18 floors that we can see,
+on a clear blue sky.
+the sun is on the left,
+illuminating that side of the building brightly
+and leaving the other side in relative shadow.
diff --git a/www/photo.causal.agency/2024-09-05/06124000009.txt b/www/photo.causal.agency/2024-09-05/06124000009.txt
new file mode 100644
index 00000000..acee212d
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000009.txt
@@ -0,0 +1,5 @@
+a huge dark brown brick building
+that is part of a hospital complex.
+it is in the sun,
+but the smaller building behind the camera
+is casting a big shadow in the middle.
diff --git a/www/photo.causal.agency/2024-09-05/06124000010.txt b/www/photo.causal.agency/2024-09-05/06124000010.txt
new file mode 100644
index 00000000..d280e6b5
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000010.txt
@@ -0,0 +1,3 @@
+some really tall, thin trees
+with branches only really high up.
+their dark green leaves are against a bright sky.
diff --git a/www/photo.causal.agency/2024-09-05/06124000014.txt b/www/photo.causal.agency/2024-09-05/06124000014.txt
new file mode 100644
index 00000000..b45b6c58
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000014.txt
@@ -0,0 +1,4 @@
+nine small square windows in a grid
+on a brown brick wall.
+a conduit runs under them
+with a light on either side.
diff --git a/www/photo.causal.agency/2024-09-05/06124000017.txt b/www/photo.causal.agency/2024-09-05/06124000017.txt
new file mode 100644
index 00000000..8b4d2ae5
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000017.txt
@@ -0,0 +1,4 @@
+a closeup of some old walkup stairs.
+the metal frame of the staircase is rusted
+and the wooden steps are decaying.
+they were once painted but almost all of it has come off.
diff --git a/www/photo.causal.agency/2024-09-05/06124000018.txt b/www/photo.causal.agency/2024-09-05/06124000018.txt
new file mode 100644
index 00000000..0a184588
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000018.txt
@@ -0,0 +1,5 @@
+a covered driveway under a building.
+the near wall is in shadow
+but the sun is playing nicely on the far part,
+out from the covered portion.
+beyond is a tree and a wooden fence.
diff --git a/www/photo.causal.agency/2024-09-05/06124000023.txt b/www/photo.causal.agency/2024-09-05/06124000023.txt
new file mode 100644
index 00000000..655ad84e
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000023.txt
@@ -0,0 +1,5 @@
+a brick wall that has a hole in it,
+which is covered by wooden planks,
+except bricks are missing from below it,
+and generally don't seem to be holding together.
+all of that behind a chain link fence right in front of it.
diff --git a/www/photo.causal.agency/2024-09-05/06124000024.txt b/www/photo.causal.agency/2024-09-05/06124000024.txt
new file mode 100644
index 00000000..65ff67be
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000024.txt
@@ -0,0 +1,5 @@
+a grey utility door on the back of a building
+below ground level,
+surrounded by vegetation on all sides,
+and a little white wooden fence
+to the left.
diff --git a/www/photo.causal.agency/2024-09-05/06124000025.txt b/www/photo.causal.agency/2024-09-05/06124000025.txt
new file mode 100644
index 00000000..66cb1aaa
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000025.txt
@@ -0,0 +1,5 @@
+a metal box affixed to a light brick wall
+with the number 1786 in black raised lettering on it.
+the surface of the metal is rusting a light orange.
+just to the right of the box,
+a bundle of black wires climbs straight up the wall.
diff --git a/www/photo.causal.agency/2024-09-05/06124000026.txt b/www/photo.causal.agency/2024-09-05/06124000026.txt
new file mode 100644
index 00000000..765411fe
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000026.txt
@@ -0,0 +1,4 @@
+what may have been a storefront
+with the address 1107.
+it's a door set into the building
+behind a locked metal grate.
diff --git a/www/photo.causal.agency/2024-09-05/06124000027.txt b/www/photo.causal.agency/2024-09-05/06124000027.txt
new file mode 100644
index 00000000..1695ade9
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000027.txt
@@ -0,0 +1,3 @@
+a metal wire sphere
+suspended by two crossing metal bars
+below some trees.
diff --git a/www/photo.causal.agency/2024-09-05/06124000032.txt b/www/photo.causal.agency/2024-09-05/06124000032.txt
new file mode 100644
index 00000000..fb83f216
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000032.txt
@@ -0,0 +1,4 @@
+looking up at a concrete building in the sun.
+it's got a detailed pattern of depth
+around the windows.
+the sky is blue.
diff --git a/www/photo.causal.agency/2024-09-05/06124000033.txt b/www/photo.causal.agency/2024-09-05/06124000033.txt
new file mode 100644
index 00000000..fb83f216
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000033.txt
@@ -0,0 +1,4 @@
+looking up at a concrete building in the sun.
+it's got a detailed pattern of depth
+around the windows.
+the sky is blue.
diff --git a/www/photo.causal.agency/2024-09-05/06124000038.txt b/www/photo.causal.agency/2024-09-05/06124000038.txt
new file mode 100644
index 00000000..30c9eb53
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000038.txt
@@ -0,0 +1,4 @@
+a selfie in some dirty reflective surface I found on the street.
+I’m holding up an analog camera to my face
+and wearing a light coloured tshirt and green little shorts.
+there’s a blue car behind me.
diff --git a/www/photo.causal.agency/2024-09-05/06124000042.txt b/www/photo.causal.agency/2024-09-05/06124000042.txt
new file mode 100644
index 00000000..535d76b0
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000042.txt
@@ -0,0 +1,3 @@
+the side of an old brick factory building
+with a fire escape going up to one window.
+the building is in shadow and the sky is white.
diff --git a/www/photo.causal.agency/2024-09-05/06124000044.txt b/www/photo.causal.agency/2024-09-05/06124000044.txt
new file mode 100644
index 00000000..67ac2df5
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/06124000044.txt
@@ -0,0 +1,8 @@
+the back of something like a building over a garage,
+with a high short window
+and a door with some steps leading down.
+the building is mostly in shadow
+except an area on the left side of the window,
+where the sun must be reflecting off something,
+given the orientation of this particular building
+and the time of day.
diff --git a/www/photo.causal.agency/2024-09-05/body b/www/photo.causal.agency/2024-09-05/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-09-05/film b/www/photo.causal.agency/2024-09-05/film
new file mode 100644
index 00000000..7c8bf080
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/film
@@ -0,0 +1 @@
+Shanghai Color 400
diff --git a/www/photo.causal.agency/2024-09-05/lens b/www/photo.causal.agency/2024-09-05/lens
new file mode 100644
index 00000000..61e7cfd8
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-05/lens
@@ -0,0 +1 @@
+Yashica ML 28–85mm ƒ/3.5-4.5
diff --git a/www/photo.causal.agency/2024-09-07/body b/www/photo.causal.agency/2024-09-07/body
new file mode 100644
index 00000000..1828b2a2
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-07/body
@@ -0,0 +1 @@
+Zenit-122
diff --git a/www/photo.causal.agency/2024-09-07/film b/www/photo.causal.agency/2024-09-07/film
new file mode 100644
index 00000000..bf3453cb
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-07/film
@@ -0,0 +1 @@
+Ilford HP5+ 400
diff --git a/www/photo.causal.agency/2024-09-07/lens b/www/photo.causal.agency/2024-09-07/lens
new file mode 100644
index 00000000..dcd0812c
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-07/lens
@@ -0,0 +1 @@
+Helios-44M-5 58mm ƒ/2
diff --git a/www/photo.causal.agency/2024-09-12/body b/www/photo.causal.agency/2024-09-12/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-12/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-09-12/film b/www/photo.causal.agency/2024-09-12/film
new file mode 100644
index 00000000..7c8bf080
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-12/film
@@ -0,0 +1 @@
+Shanghai Color 400
diff --git a/www/photo.causal.agency/2024-09-12/lens b/www/photo.causal.agency/2024-09-12/lens
new file mode 100644
index 00000000..b7c8829c
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-12/lens
@@ -0,0 +1 @@
+Yashica ML 42–75mm ƒ/3.5–4.5
diff --git a/www/photo.causal.agency/2024-09-14/body b/www/photo.causal.agency/2024-09-14/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-14/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-09-14/film b/www/photo.causal.agency/2024-09-14/film
new file mode 100644
index 00000000..0fb06431
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-14/film
@@ -0,0 +1 @@
+Fomapan Creative 200, Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-09-14/lens b/www/photo.causal.agency/2024-09-14/lens
new file mode 100644
index 00000000..b7c8829c
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-14/lens
@@ -0,0 +1 @@
+Yashica ML 42–75mm ƒ/3.5–4.5
diff --git a/www/photo.causal.agency/2024-09-15/body b/www/photo.causal.agency/2024-09-15/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-15/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-09-15/film b/www/photo.causal.agency/2024-09-15/film
new file mode 100644
index 00000000..c3e0e2b4
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-15/film
@@ -0,0 +1 @@
+Harman Phoenix 200, Ilford FP4 Plus 125
diff --git a/www/photo.causal.agency/2024-09-15/lens b/www/photo.causal.agency/2024-09-15/lens
new file mode 100644
index 00000000..b7c8829c
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-15/lens
@@ -0,0 +1 @@
+Yashica ML 42–75mm ƒ/3.5–4.5
diff --git a/www/photo.causal.agency/2024-09-22/body b/www/photo.causal.agency/2024-09-22/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-22/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-09-22/film b/www/photo.causal.agency/2024-09-22/film
new file mode 100644
index 00000000..44fd8200
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-22/film
@@ -0,0 +1 @@
+Shanghai Color 400, Ilford Delta 100
diff --git a/www/photo.causal.agency/2024-09-22/lens b/www/photo.causal.agency/2024-09-22/lens
new file mode 100644
index 00000000..d1617296
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-22/lens
@@ -0,0 +1 @@
+Pentacon 50mm ƒ/1.8
diff --git a/www/photo.causal.agency/2024-09-28/body b/www/photo.causal.agency/2024-09-28/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-28/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-09-28/film b/www/photo.causal.agency/2024-09-28/film
new file mode 100644
index 00000000..186deeaa
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-28/film
@@ -0,0 +1 @@
+Wolfen NC500
diff --git a/www/photo.causal.agency/2024-09-28/lens b/www/photo.causal.agency/2024-09-28/lens
new file mode 100644
index 00000000..d1617296
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-28/lens
@@ -0,0 +1 @@
+Pentacon 50mm ƒ/1.8
diff --git a/www/photo.causal.agency/2024-09-29/body b/www/photo.causal.agency/2024-09-29/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-29/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-09-29/film b/www/photo.causal.agency/2024-09-29/film
new file mode 100644
index 00000000..75a90c86
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-29/film
@@ -0,0 +1 @@
+Ilford FP4 Plus 125
diff --git a/www/photo.causal.agency/2024-09-29/lens b/www/photo.causal.agency/2024-09-29/lens
new file mode 100644
index 00000000..038971f7
--- /dev/null
+++ b/www/photo.causal.agency/2024-09-29/lens
@@ -0,0 +1 @@
+Takumar 35mm ƒ/3.5, Takumar 135mm ƒ/3.5
diff --git a/www/photo.causal.agency/2024-10-01/body b/www/photo.causal.agency/2024-10-01/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-01/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-10-01/film b/www/photo.causal.agency/2024-10-01/film
new file mode 100644
index 00000000..dd589471
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-01/film
@@ -0,0 +1 @@
+Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-10-01/lens b/www/photo.causal.agency/2024-10-01/lens
new file mode 100644
index 00000000..a88822d3
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-01/lens
@@ -0,0 +1 @@
+Takumar 135mm ƒ/3.5, Pentacon 50mm ƒ/1.8
diff --git a/www/photo.causal.agency/2024-10-05/body b/www/photo.causal.agency/2024-10-05/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-05/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-10-05/film b/www/photo.causal.agency/2024-10-05/film
new file mode 100644
index 00000000..6bb4ba69
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-05/film
@@ -0,0 +1 @@
+Ferrania P30, Harman Phoenix
diff --git a/www/photo.causal.agency/2024-10-05/lens b/www/photo.causal.agency/2024-10-05/lens
new file mode 100644
index 00000000..d1617296
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-05/lens
@@ -0,0 +1 @@
+Pentacon 50mm ƒ/1.8
diff --git a/www/photo.causal.agency/2024-10-06/body b/www/photo.causal.agency/2024-10-06/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-06/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-10-06/film b/www/photo.causal.agency/2024-10-06/film
new file mode 100644
index 00000000..968fca45
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-06/film
@@ -0,0 +1 @@
+CineStill 800T
diff --git a/www/photo.causal.agency/2024-10-06/lens b/www/photo.causal.agency/2024-10-06/lens
new file mode 100644
index 00000000..d1617296
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-06/lens
@@ -0,0 +1 @@
+Pentacon 50mm ƒ/1.8
diff --git a/www/photo.causal.agency/2024-10-12/body b/www/photo.causal.agency/2024-10-12/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-12/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-10-12/film b/www/photo.causal.agency/2024-10-12/film
new file mode 100644
index 00000000..7c8bf080
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-12/film
@@ -0,0 +1 @@
+Shanghai Color 400
diff --git a/www/photo.causal.agency/2024-10-12/lens b/www/photo.causal.agency/2024-10-12/lens
new file mode 100644
index 00000000..87eda797
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-12/lens
@@ -0,0 +1 @@
+Yashica MC 35–70mm ƒ/3.5–4.5
diff --git a/www/photo.causal.agency/2024-10-17/body b/www/photo.causal.agency/2024-10-17/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-17/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-10-17/film b/www/photo.causal.agency/2024-10-17/film
new file mode 100644
index 00000000..fb690ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-17/film
@@ -0,0 +1 @@
+Fomapan Creative 200
diff --git a/www/photo.causal.agency/2024-10-17/lens b/www/photo.causal.agency/2024-10-17/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-17/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-10-20/body b/www/photo.causal.agency/2024-10-20/body
new file mode 100644
index 00000000..1828b2a2
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-20/body
@@ -0,0 +1 @@
+Zenit-122
diff --git a/www/photo.causal.agency/2024-10-20/film b/www/photo.causal.agency/2024-10-20/film
new file mode 100644
index 00000000..7c8bf080
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-20/film
@@ -0,0 +1 @@
+Shanghai Color 400
diff --git a/www/photo.causal.agency/2024-10-20/lens b/www/photo.causal.agency/2024-10-20/lens
new file mode 100644
index 00000000..cf233451
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-20/lens
@@ -0,0 +1 @@
+Helios 44M-5 58mm ƒ/2, SMC Takumar 35mm ƒ/3.5
diff --git a/www/photo.causal.agency/2024-10-23/body b/www/photo.causal.agency/2024-10-23/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-23/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-10-23/film b/www/photo.causal.agency/2024-10-23/film
new file mode 100644
index 00000000..7c8bf080
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-23/film
@@ -0,0 +1 @@
+Shanghai Color 400
diff --git a/www/photo.causal.agency/2024-10-23/lens b/www/photo.causal.agency/2024-10-23/lens
new file mode 100644
index 00000000..abcaed38
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-23/lens
@@ -0,0 +1 @@
+Super-Takumar 135mm ƒ/3.5, Pentacon 50mm ƒ/1.8
diff --git a/www/photo.causal.agency/2024-10-27/body b/www/photo.causal.agency/2024-10-27/body
new file mode 100644
index 00000000..eafb759d
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-27/body
@@ -0,0 +1 @@
+Praktica MTL3
diff --git a/www/photo.causal.agency/2024-10-27/film b/www/photo.causal.agency/2024-10-27/film
new file mode 100644
index 00000000..ad59eb5e
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-27/film
@@ -0,0 +1 @@
+Reflx Lab 800T
diff --git a/www/photo.causal.agency/2024-10-27/lens b/www/photo.causal.agency/2024-10-27/lens
new file mode 100644
index 00000000..d1617296
--- /dev/null
+++ b/www/photo.causal.agency/2024-10-27/lens
@@ -0,0 +1 @@
+Pentacon 50mm ƒ/1.8
diff --git a/www/photo.causal.agency/2024-11-02/body b/www/photo.causal.agency/2024-11-02/body
new file mode 100644
index 00000000..6a2a5ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-02/body
@@ -0,0 +1 @@
+Yashica FX-2
diff --git a/www/photo.causal.agency/2024-11-02/film b/www/photo.causal.agency/2024-11-02/film
new file mode 100644
index 00000000..cea1eb40
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-02/film
@@ -0,0 +1 @@
+Kodak Portra 800 (shot at 1600)
diff --git a/www/photo.causal.agency/2024-11-02/lens b/www/photo.causal.agency/2024-11-02/lens
new file mode 100644
index 00000000..13f1fc49
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-02/lens
@@ -0,0 +1 @@
+Yashica DSB 50mm ƒ/1.9
diff --git a/www/photo.causal.agency/2024-11-06/body b/www/photo.causal.agency/2024-11-06/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-06/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-11-06/film b/www/photo.causal.agency/2024-11-06/film
new file mode 100644
index 00000000..7c8bf080
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-06/film
@@ -0,0 +1 @@
+Shanghai Color 400
diff --git a/www/photo.causal.agency/2024-11-06/lens b/www/photo.causal.agency/2024-11-06/lens
new file mode 100644
index 00000000..f4270bba
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-06/lens
@@ -0,0 +1 @@
+Yashica ML 50mm ƒ/2
diff --git a/www/photo.causal.agency/2024-11-09/body b/www/photo.causal.agency/2024-11-09/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-09/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-11-09/film b/www/photo.causal.agency/2024-11-09/film
new file mode 100644
index 00000000..fb690ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-09/film
@@ -0,0 +1 @@
+Fomapan Creative 200
diff --git a/www/photo.causal.agency/2024-11-09/lens b/www/photo.causal.agency/2024-11-09/lens
new file mode 100644
index 00000000..f4270bba
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-09/lens
@@ -0,0 +1 @@
+Yashica ML 50mm ƒ/2
diff --git a/www/photo.causal.agency/2024-11-12/body b/www/photo.causal.agency/2024-11-12/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-12/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-11-12/film b/www/photo.causal.agency/2024-11-12/film
new file mode 100644
index 00000000..cf9df85c
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-12/film
@@ -0,0 +1 @@
+Flic Film Elektra 100 (Kodak Aerocolor IV)
diff --git a/www/photo.causal.agency/2024-11-12/lens b/www/photo.causal.agency/2024-11-12/lens
new file mode 100644
index 00000000..31116f95
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-12/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm ƒ/1.7
diff --git a/www/photo.causal.agency/2024-11-16/body b/www/photo.causal.agency/2024-11-16/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-16/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-11-16/film b/www/photo.causal.agency/2024-11-16/film
new file mode 100644
index 00000000..c0f6ee30
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-16/film
@@ -0,0 +1 @@
+Flic Film Elektra 100 (Kodak Aerocolor IV), Harman Phoenix 200
diff --git a/www/photo.causal.agency/2024-11-16/lens b/www/photo.causal.agency/2024-11-16/lens
new file mode 100644
index 00000000..31116f95
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-16/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm ƒ/1.7
diff --git a/www/photo.causal.agency/2024-11-18/body b/www/photo.causal.agency/2024-11-18/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-18/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-11-18/film b/www/photo.causal.agency/2024-11-18/film
new file mode 100644
index 00000000..ada88ac3
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-18/film
@@ -0,0 +1 @@
+Ferrania P30
diff --git a/www/photo.causal.agency/2024-11-18/lens b/www/photo.causal.agency/2024-11-18/lens
new file mode 100644
index 00000000..31116f95
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-18/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm ƒ/1.7
diff --git a/www/photo.causal.agency/2024-11-23/body b/www/photo.causal.agency/2024-11-23/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-23/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-11-23/film b/www/photo.causal.agency/2024-11-23/film
new file mode 100644
index 00000000..d198f26d
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-23/film
@@ -0,0 +1 @@
+Ferrania P33
diff --git a/www/photo.causal.agency/2024-11-23/lens b/www/photo.causal.agency/2024-11-23/lens
new file mode 100644
index 00000000..f4270bba
--- /dev/null
+++ b/www/photo.causal.agency/2024-11-23/lens
@@ -0,0 +1 @@
+Yashica ML 50mm ƒ/2
diff --git a/www/photo.causal.agency/2024-12-21/body b/www/photo.causal.agency/2024-12-21/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-12-21/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-12-21/film b/www/photo.causal.agency/2024-12-21/film
new file mode 100644
index 00000000..fb690ad8
--- /dev/null
+++ b/www/photo.causal.agency/2024-12-21/film
@@ -0,0 +1 @@
+Fomapan Creative 200
diff --git a/www/photo.causal.agency/2024-12-21/lens b/www/photo.causal.agency/2024-12-21/lens
new file mode 100644
index 00000000..3bee8822
--- /dev/null
+++ b/www/photo.causal.agency/2024-12-21/lens
@@ -0,0 +1 @@
+Yashica ML 50mm ƒ/2, Yashica DSB 28mm ƒ/2.8
diff --git a/www/photo.causal.agency/2024-12-28/body b/www/photo.causal.agency/2024-12-28/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2024-12-28/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2024-12-28/film b/www/photo.causal.agency/2024-12-28/film
new file mode 100644
index 00000000..ad59eb5e
--- /dev/null
+++ b/www/photo.causal.agency/2024-12-28/film
@@ -0,0 +1 @@
+Reflx Lab 800T
diff --git a/www/photo.causal.agency/2024-12-28/lens b/www/photo.causal.agency/2024-12-28/lens
new file mode 100644
index 00000000..a64ba4b7
--- /dev/null
+++ b/www/photo.causal.agency/2024-12-28/lens
@@ -0,0 +1 @@
+Yashica DSB 28mm f/2.8
diff --git a/www/photo.causal.agency/2025-01-18/body b/www/photo.causal.agency/2025-01-18/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-01-18/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-01-18/film b/www/photo.causal.agency/2025-01-18/film
new file mode 100644
index 00000000..c20afa1a
--- /dev/null
+++ b/www/photo.causal.agency/2025-01-18/film
@@ -0,0 +1 @@
+Reflx Lab 400D
diff --git a/www/photo.causal.agency/2025-01-18/lens b/www/photo.causal.agency/2025-01-18/lens
new file mode 100644
index 00000000..10ce84b5
--- /dev/null
+++ b/www/photo.causal.agency/2025-01-18/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7, Yashica DSB 135mm f/2.8
diff --git a/www/photo.causal.agency/2025-01-26/body b/www/photo.causal.agency/2025-01-26/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-01-26/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-01-26/film b/www/photo.causal.agency/2025-01-26/film
new file mode 100644
index 00000000..0d5a24a4
--- /dev/null
+++ b/www/photo.causal.agency/2025-01-26/film
@@ -0,0 +1 @@
+Street Candy ATM400
diff --git a/www/photo.causal.agency/2025-01-26/lens b/www/photo.causal.agency/2025-01-26/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-01-26/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/2025-02-08/body b/www/photo.causal.agency/2025-02-08/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-08/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-02-08/film b/www/photo.causal.agency/2025-02-08/film
new file mode 100644
index 00000000..6b8ba9dc
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-08/film
@@ -0,0 +1 @@
+Kodak Portra 800
diff --git a/www/photo.causal.agency/2025-02-08/lens b/www/photo.causal.agency/2025-02-08/lens
new file mode 100644
index 00000000..08cc1075
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-08/lens
@@ -0,0 +1 @@
+Yashica ML 42-75mm f/3.5-4.5
diff --git a/www/photo.causal.agency/2025-02-11/body b/www/photo.causal.agency/2025-02-11/body
new file mode 100644
index 00000000..1828b2a2
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-11/body
@@ -0,0 +1 @@
+Zenit-122
diff --git a/www/photo.causal.agency/2025-02-11/film b/www/photo.causal.agency/2025-02-11/film
new file mode 100644
index 00000000..fb690ad8
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-11/film
@@ -0,0 +1 @@
+Fomapan Creative 200
diff --git a/www/photo.causal.agency/2025-02-11/lens b/www/photo.causal.agency/2025-02-11/lens
new file mode 100644
index 00000000..25cae06f
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-11/lens
@@ -0,0 +1 @@
+Helios-44M-5 58mm f/2
diff --git a/www/photo.causal.agency/2025-02-17/body b/www/photo.causal.agency/2025-02-17/body
new file mode 100644
index 00000000..1828b2a2
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-17/body
@@ -0,0 +1 @@
+Zenit-122
diff --git a/www/photo.causal.agency/2025-02-17/film b/www/photo.causal.agency/2025-02-17/film
new file mode 100644
index 00000000..8cf5c5b8
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-17/film
@@ -0,0 +1 @@
+Fomapan Classic 100
diff --git a/www/photo.causal.agency/2025-02-17/lens b/www/photo.causal.agency/2025-02-17/lens
new file mode 100644
index 00000000..25cae06f
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-17/lens
@@ -0,0 +1 @@
+Helios-44M-5 58mm f/2
diff --git a/www/photo.causal.agency/2025-02-23/body b/www/photo.causal.agency/2025-02-23/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-23/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-02-23/film b/www/photo.causal.agency/2025-02-23/film
new file mode 100644
index 00000000..75a90c86
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-23/film
@@ -0,0 +1 @@
+Ilford FP4 Plus 125
diff --git a/www/photo.causal.agency/2025-02-23/lens b/www/photo.causal.agency/2025-02-23/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-23/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/2025-02-25/body b/www/photo.causal.agency/2025-02-25/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-25/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-02-25/film b/www/photo.causal.agency/2025-02-25/film
new file mode 100644
index 00000000..ea743873
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-25/film
@@ -0,0 +1 @@
+Flic Film Elektra (Kodak Aerocolor)
diff --git a/www/photo.causal.agency/2025-02-25/lens b/www/photo.causal.agency/2025-02-25/lens
new file mode 100644
index 00000000..033bc748
--- /dev/null
+++ b/www/photo.causal.agency/2025-02-25/lens
@@ -0,0 +1 @@
+Yashica ML 50mm f/2
diff --git a/www/photo.causal.agency/2025-03-15/body b/www/photo.causal.agency/2025-03-15/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-15/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-03-15/film b/www/photo.causal.agency/2025-03-15/film
new file mode 100644
index 00000000..58e2f25c
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-15/film
@@ -0,0 +1 @@
+Kodak Ektar 100, Shanghai Color 400
diff --git a/www/photo.causal.agency/2025-03-15/lens b/www/photo.causal.agency/2025-03-15/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-15/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/2025-03-16/body b/www/photo.causal.agency/2025-03-16/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-16/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-03-16/film b/www/photo.causal.agency/2025-03-16/film
new file mode 100644
index 00000000..c2518f1e
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-16/film
@@ -0,0 +1 @@
+Shanghai Color 400, Fomapan Creative 200
diff --git a/www/photo.causal.agency/2025-03-16/lens b/www/photo.causal.agency/2025-03-16/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-16/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/2025-03-18/body b/www/photo.causal.agency/2025-03-18/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-18/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-03-18/film b/www/photo.causal.agency/2025-03-18/film
new file mode 100644
index 00000000..fb690ad8
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-18/film
@@ -0,0 +1 @@
+Fomapan Creative 200
diff --git a/www/photo.causal.agency/2025-03-18/lens b/www/photo.causal.agency/2025-03-18/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-18/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/2025-03-19/body b/www/photo.causal.agency/2025-03-19/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-19/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-03-19/film b/www/photo.causal.agency/2025-03-19/film
new file mode 100644
index 00000000..ada88ac3
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-19/film
@@ -0,0 +1 @@
+Ferrania P30
diff --git a/www/photo.causal.agency/2025-03-19/lens b/www/photo.causal.agency/2025-03-19/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-19/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/2025-03-22/body b/www/photo.causal.agency/2025-03-22/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-22/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-03-22/film b/www/photo.causal.agency/2025-03-22/film
new file mode 100644
index 00000000..618ed9ba
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-22/film
@@ -0,0 +1 @@
+Ferrania P30, Shanghai GP3 100, AristaEDU Ultra 400
diff --git a/www/photo.causal.agency/2025-03-22/lens b/www/photo.causal.agency/2025-03-22/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-22/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/2025-03-23/body b/www/photo.causal.agency/2025-03-23/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-23/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/2025-03-23/film b/www/photo.causal.agency/2025-03-23/film
new file mode 100644
index 00000000..0352ae38
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-23/film
@@ -0,0 +1 @@
+Fujifilm Acros 100 II, Rollei Superpan 200
diff --git a/www/photo.causal.agency/2025-03-23/lens b/www/photo.causal.agency/2025-03-23/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/2025-03-23/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/c35/body b/www/photo.causal.agency/c35/body
new file mode 100644
index 00000000..3676b877
--- /dev/null
+++ b/www/photo.causal.agency/c35/body
@@ -0,0 +1 @@
+Konica C35 Automatic
diff --git a/www/photo.causal.agency/c35/lens b/www/photo.causal.agency/c35/lens
new file mode 100644
index 00000000..3fef9a43
--- /dev/null
+++ b/www/photo.causal.agency/c35/lens
@@ -0,0 +1 @@
+Konica Hexanon 38mm f/2.8
diff --git a/www/photo.causal.agency/fx-3/body b/www/photo.causal.agency/fx-3/body
new file mode 100644
index 00000000..0962ee7d
--- /dev/null
+++ b/www/photo.causal.agency/fx-3/body
@@ -0,0 +1 @@
+Yashica FX-3
diff --git a/www/photo.causal.agency/fx-3/lens b/www/photo.causal.agency/fx-3/lens
new file mode 100644
index 00000000..eaab4375
--- /dev/null
+++ b/www/photo.causal.agency/fx-3/lens
@@ -0,0 +1 @@
+Carl Zeiss Planar T* 50mm f/1.7
diff --git a/www/photo.causal.agency/gear.html b/www/photo.causal.agency/gear.html
new file mode 100644
index 00000000..e058d341
--- /dev/null
+++ b/www/photo.causal.agency/gear.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Photography Equipment</title>
+<style>
+html { color: #bbb; background-color: black; font-family: monospace; }
+body { max-width: 76ch; margin: auto; }
+</style>
+
+<h1>Photography Equipment</h1>
+<p>
+this is a (probably incomplete) list of equipment I use to Do Photography.
+
+<h2>Cameras</h2>
+<ul>
+<li>Yashica FX-3 (every day)
+<li>Konica C35 Automatic (Hexanon 38mm f/2.8) (every day)
+<li>Praktica MTL3 (probably on loan to a friend)
+<li>Zenit-122
+<li>Yashica FX-2
+</ul>
+
+<h2>Lenses</h2>
+<ul>
+<li>Carl Zeis Planar T* 50mm f/1.7 (FX-3 default)
+<li>Yashica DSB 50mm f/1.9 (FX-2 kit lens)
+<li>Helios-44M-5 58mm f/2 (Zenit-122 kit lens)
+<li>Pentacon 50mm f/1.8 (MTL3 kit lens)
+<li>Osawa MC 70-210mm f/4-5 (C/Y)
+<li>Takumar SMC 35mm f/3.5
+<li>Super-Takumar 135mm f/3.5
+<li>Yashica ML 28-85mm f/3.5-4.5 (wonky focus at 28mm)
+<li>Yashica ML 42-75mm f/3.5-4.5
+<li>Yashica MC 35-70mm f/3.5-4.5 (bad aperture)
+<li>Yashica ML 50mm f/2 (sticky aperture)
+<li>Yashica DSB 28mm f/2.8
+<li>Yashica DSB 135mm f/2.8
+<li>Yashica ML Macro 55mm f/2.8
+<li>Yashica ML 28mm f/2.8
+<li>Yashica ML 75-150mm f/4
+</ul>
+
+<h2>Flash</h2>
+<ul>
+<li>Reflx Lab Simple Flash
+<li>Starblitz 318M
+</ul>
+
+<h2>Tripod</h2>
+<ul>
+<li>Sirui Traveler 5C
+</ul>
+
+<h2>Scanning</h2>
+<ul>
+<li>Filmomat SmartConvert
+<li>Canon EOS Rebel SL3
+<li>Yashica ML Macro 55mm f/2.8 (at f/11)
+<li>Yashica 13mm extension tube (also have 20mm and 27mm)
+<li>Urth C/Y-EF adapter
+<li>Skier CS-700 copy stand
+<li>Valoi 135 film holder
+<li>CineStill CS-Lite
+<li>the box the CS-Lite came in
+</ul>
diff --git a/www/photo.causal.agency/generate.sh b/www/photo.causal.agency/generate.sh
new file mode 100644
index 00000000..83a3128b
--- /dev/null
+++ b/www/photo.causal.agency/generate.sh
@@ -0,0 +1,284 @@
+#!/bin/sh
+set -eu
+
+mkdir -p static/preview static/thumbnail
+
+resize() {
+	local photo=$1 size=$2 output=$3
+	if ! test -f $output; then
+		# FIXME: convert complains about not understanding XML
+		echo $output >&2
+		convert $photo -auto-orient -thumbnail $size $output 2>/dev/null ||:
+	fi
+}
+
+preview() {
+	local photo=$1
+	local preview=preview/${photo##*/}
+	resize $photo 1500000@ static/$preview
+	echo $preview
+}
+
+thumbnail() {
+	local photo=$1
+	local thumbnail=thumbnail/${photo##*/}
+	resize $photo 60000@ static/$thumbnail
+	echo $thumbnail
+}
+
+encode() {
+	sed '
+		s/&/\&amp;/g
+		s/</\&lt;/g
+		s/"/\&quot;/g
+	' "$@"
+}
+
+page_title() {
+	case $1 in
+		(leader) echo 'Film Leader';;
+		(20*) date -j -f '%F' $1 '+%B %e, %Y';;
+		(0*) echo Roll $(dc -e "${1}p");;
+	esac
+}
+
+page_head() {
+	local page=$1
+	local title=$(page_title $page)
+	local date body lens film note
+
+	if test -f $page/date; then
+		date=$(sed 's/\([0-9]\)-\([0-9]\)/\1–\2/g' $page/date | encode)
+	fi
+	if test -f $page/body; then
+		body=$(encode $page/body)
+	fi
+	if test -f $page/lens; then
+		lens=$(
+			sed '
+				s,f/,ƒ/,g
+				s/\([0-9]\)-\([0-9]\)/\1–\2/g
+			' $page/lens |
+			encode
+		)
+	else
+		lens=$(
+			identify -format '%[EXIF:LensModel]' \
+				$page/$(ls -1 $page | head -n 1) 2>/dev/null |
+			sed '
+				s/\([A-Z]\)\([0-9]\)/\1 \2/
+				s,f/,ƒ/,
+				s/\([0-9]\)-\([0-9]\)/\1–\2/g
+			' |
+			encode
+		)
+	fi
+	if test -f $page/film; then
+		film=$(encode $page/film)
+	fi
+	if test -f $page/note; then
+		note=$(encode $page/note)
+	fi
+
+	cat <<-EOF
+	<!DOCTYPE html>
+	<meta charset="utf-8">
+	<meta name="viewport" content="width=device-width, initial-scale=1.0">
+	<link rel="alternate" type="application/atom+xml" href="../feed.atom">
+	<title>${title}</title>
+	<style>
+	html { color: #bbb; background-color: black; font-family: monospace; }
+	p { text-align: center; }
+	figure { margin: 1em; padding-top: 0.5em; text-align: center; }
+	img { max-width: calc(100vw - 2.5em); max-height: calc(100vh - 2.5em); }
+	details { max-width: 78ch; margin: 0.5em auto; }
+	</style>
+	<h1>${title}</h1>
+	<p>${date:+📆 }${date:-} 📷 ${body:-}${body:+ 🔘 }${lens:-}${film:+ 🎞️ }${film:-}</p>
+	${note:+<p>}${note:-}${note:+</p>}
+	EOF
+}
+
+photo_info() {
+	local photo=$1
+	ExposureTime=
+	FNumber=
+	FocalLength=
+	PhotographicSensitivity=
+	eval $(
+		identify -format '%[EXIF:*]' $photo 2>/dev/null |
+		grep -E 'ExposureTime|FNumber|FocalLength|PhotographicSensitivity' |
+		sed 's/^exif://'
+	)
+}
+
+photo_id() {
+	local photo=$1
+	photo=${photo##*/}
+	photo=${photo%%.*}
+	echo $photo
+}
+
+page_photo() {
+	local photo=$1 preview=$2 description=$3
+	photo_info $photo
+	cat <<-EOF
+	<figure id="$(photo_id $photo)">
+		<a href="${photo##*/}">
+	EOF
+	if test -f $description; then
+		cat <<-EOF
+			<img src="../${preview}" alt="$(encode $description)">
+		EOF
+	else
+		cat <<-EOF
+			<img src="../${preview}">
+		EOF
+	fi
+	cat <<-EOF
+		</a>
+		<figcaption>
+	EOF
+	if test -n "${ExposureTime}"; then
+		cat <<-EOF
+			${ExposureTime} ·
+			ƒ/$(bc -S 1 -e ${FNumber}) ·
+			$(bc -e ${FocalLength}) mm ·
+			${PhotographicSensitivity} ISO
+		EOF
+	fi
+	if test -f $description; then
+		cat <<-EOF
+			<details>
+				<summary>description</summary>
+				$(encode $description)
+			</details>
+		EOF
+	fi
+	cat <<-EOF
+		</figcaption>
+	</figure>
+	EOF
+}
+
+index_head() {
+	cat <<-EOF
+	<!DOCTYPE html>
+	<meta charset="utf-8">
+	<meta name="viewport" content="width=device-width, initial-scale=1.0">
+	<link rel="alternate" type="application/atom+xml" href="feed.atom">
+	<title>Photos</title>
+	<style>
+	html { color: #bbb; background-color: black; font-family: sans-serif; }
+	a { text-decoration: none; color: inherit; }
+	</style>
+	EOF
+}
+
+index_page() {
+	local date=$1 root=${2:-}
+	cat <<-EOF
+	<h1><a href="${root}${root:+/}${date}/">$(page_title $date)</a></h1>
+	EOF
+}
+
+index_photo() {
+	local date=$1 photo=$2 thumbnail=$3 root=${4:-}
+	cat <<-EOF
+	<a href="${root}${root:+/}${date}/#$(photo_id $photo)">
+		<img src="${root}${root:+/}${thumbnail}">
+	</a>
+	EOF
+}
+
+Root=https://photo.causal.agency
+
+atom_head() {
+	local updated=$(date -u '+%FT%TZ')
+	cat <<-EOF
+	<?xml version="1.0" encoding="utf-8"?>
+	<feed xmlns="http://www.w3.org/2005/Atom">
+	<title>Photos</title>
+	<author><name>june</name><email>june@causal.agency</email></author>
+	<link href="${Root}"/>
+	<link rel="self" href="${Root}/feed.atom"/>
+	<id>${Root}/</id>
+	<updated>${updated}</updated>
+	EOF
+}
+
+atom_entry_head() {
+	local date=$1
+	local updated=$(
+		date -ju -f '%s' $(stat -f '%m' static/${date}/index.html) '+%FT%TZ'
+	)
+	cat <<-EOF
+	<entry>
+	<title>$(page_title $date)</title>
+	<link href="${Root}/${date}/"/>
+	<id>${Root}/${date}/</id>
+	<updated>${updated}</updated>
+	<content type="html">
+	EOF
+}
+
+atom_entry_tail() {
+	cat <<-EOF
+	</content>
+	</entry>
+	EOF
+}
+
+atom_tail() {
+	cat <<-EOF
+	</feed>
+	EOF
+}
+
+set --
+for entry in 20* 0*; do
+	mkdir -p static/${entry}
+	page=static/${entry}/index.html
+	if ! test -f $page; then
+		echo $page >&2
+		page_head $entry >$page
+		for photo in ${entry}/*.[Jj][Pp][Gg]; do
+			preview=$(preview $photo)
+			if ! test -f static/${photo}; then
+				ln $photo static/${photo}
+			fi
+			page_photo $photo $preview ${photo%.[Jj][Pp][Gg]}.txt >>$page
+		done
+	fi
+	set -- $entry "$@"
+done
+
+mkdir -p static/leader
+page=static/leader/index.html
+if [ leader -nt $page ]; then
+	echo $page >&2
+	page_head leader >$page
+	for photo in leader/*.[Jj][Pp][Gg]; do
+		preview=$(preview $photo)
+		if ! test -f static/${photo}; then
+			ln $photo static/${photo}
+		fi
+		page_photo $photo $preview xxx >>$page
+	done
+fi
+
+echo static/index.html >&2
+index_head >static/index.html
+echo static/feed.atom >&2
+atom_head >static/feed.atom
+for date; do
+	index_page $date >>static/index.html
+	atom_entry_head $date >>static/feed.atom
+	for photo in ${date}/*.[Jj][Pp][Gg]; do
+		thumbnail=$(thumbnail $photo)
+		index_photo $date $photo $thumbnail >>static/index.html
+		index_photo $date $photo $thumbnail $Root | encode >>static/feed.atom
+	done
+	atom_entry_tail >>static/feed.atom
+done
+atom_tail >>static/feed.atom
diff --git a/www/photo.causal.agency/mastodon.sh b/www/photo.causal.agency/mastodon.sh
new file mode 100644
index 00000000..1eaa1114
--- /dev/null
+++ b/www/photo.causal.agency/mastodon.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+set -eu
+
+Instance=https://tilde.zone
+Root=${1:-static}
+
+if ! test -f app.json; then
+	echo 'No app.json!' >&2
+	exit 1
+fi
+chmod 600 app.json
+
+if ! test -f token.json; then
+	client_id=$(jq -r .client_id app.json)
+	client_secret=$(jq -r .client_secret app.json)
+	echo "Please open ${Instance}/oauth/authorize?client_id=${client_id}&scope=write&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code"
+	printf 'Enter code: '
+	read -r code
+	curl -Ss -X POST \
+		-F 'grant_type=authorization_code' \
+		-F "client_id=${client_id}" \
+		-F "client_secret=${client_secret}" \
+		-F 'redirect_uri=urn:ietf:wg:oauth:2.0:oob' \
+		-F "code=${code}" \
+		${Instance}/oauth/token >token.json
+fi
+chmod 600 token.json
+
+access_token=$(jq -r .access_token token.json)
+
+if ! test -f posted.txt; then
+	touch posted.txt
+fi
+
+photo=$(
+	find ${Root} -type f -path '*/0*/*.jpg' |
+	sort | comm -13 posted.txt - | head -n 1
+)
+preview=${Root}/preview/${photo##*/}
+
+media_id=$(
+	curl -Ss -X POST \
+		-H "Authorization: Bearer ${access_token}" \
+		-F "file=@${preview}" \
+		${Instance}/api/v2/media |
+	jq -r .id
+)
+
+curl -Ss -X POST \
+	-H "Authorization: Bearer ${access_token}" \
+	-F "media_ids[]=${media_id}" \
+	${Instance}/api/v1/statuses >/dev/null
+
+echo ${photo} >>posted.txt
diff --git a/www/photo.causal.agency/rsync.sh b/www/photo.causal.agency/rsync.sh
new file mode 100644
index 00000000..957911d2
--- /dev/null
+++ b/www/photo.causal.agency/rsync.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -eu
+
+sh generate.sh
+rsync -av static/ scout:/var/www/photo.causal.agency
diff --git a/www/photo.causal.agency/trips.html b/www/photo.causal.agency/trips.html
new file mode 100644
index 00000000..d65aeaef
--- /dev/null
+++ b/www/photo.causal.agency/trips.html
@@ -0,0 +1,365 @@
+<!DOCTYPE html>
+<title>Photo Trips</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+<style>
+body {
+	font-family: sans-serif;
+	line-height: 1.5em;
+	max-width: 52ch;
+}
+input, button, select { font-size: 100%; }
+form {
+	display: grid;
+	grid-template-columns: auto 1fr;
+	gap: 0.5em 1ch;
+}
+input[type="number"] { width: 5ch; }
+#trip-lens { width: 100%; }
+#lens-length { width: 7ch; }
+#lens-aperture { width: 8ch; }
+</style>
+
+<section id="rolls">
+<h1>Rolls</h1>
+<ul>
+</ul>
+
+<form>
+<label for="roll-body">Camera:</label>
+<select id="roll-body" class="body" required>
+</select>
+<label for="roll-film">Film:</label>
+<input id="roll-film" list="films" required>
+<span>Exposures:</span>
+<span>
+<input id="roll-36" type="radio" name="roll-exposures" value="36" checked>
+<label for="roll-36">36</label>
+<input id="roll-27" type="radio" name="roll-exposures" value="27">
+<label for="roll-27">27</label>
+<input id="roll-24" type="radio" name="roll-exposures" value="24">
+<label for="roll-24">24</label>
+<input id="roll-12" type="radio" name="roll-exposures" value="12">
+<label for="roll-12">12</label>
+</span>
+<button type="button" onclick="loadRoll()">Load</button>
+</form>
+
+<datalist id="films">
+	<option>Ferrania P30 80</option>
+	<option>Flic Film Elektra 100</option>
+	<option>Ilford FP4 Plus 125</option>
+	<option>Fomapan Creative 200</option>
+	<option>Harman Phoenix 200</option>
+	<option>Shanghai Color 400</option>
+	<option>Reflx Lab 800T</option>
+</datalist>
+</section>
+
+<section id="trips">
+<h1>Trips</h1>
+
+<form>
+<label for="trip-date">Date:</label>
+<input id="trip-date" type="date" required>
+<label for="trip-body">Camera:</label>
+<select id="trip-body" class="body" onchange="setTripBody()" required>
+</select>
+<label for="trip-lens">Lens:</label>
+<select id="trip-lens" required>
+</select>
+<label for="trip-film">Film:</label>
+<input id="trip-film" readonly required>
+<label for="trip-first">Exposures:</label>
+<span>
+<input id="trip-first" type="number" required min="0" max="36">
+–
+<input id="trip-last" type="number" required min="0" max="36">
+</span>
+<label for="trip-note">Note:</label>
+<input id="trip-note">
+<button type="button" onclick="addTrip()">Record</button>
+</form>
+
+<ul>
+</ul>
+</section>
+
+<section id="bodies">
+<h1>Cameras</h1>
+<ul>
+</ul>
+
+<form>
+	<label for="body-name">Name:</label>
+	<input id="body-name" required>
+	<label for="body-mount">Mount:</label>
+	<input id="body-mount" list="mounts" required>
+	<button type="button" onclick="addBody()">Add</button>
+</form>
+
+<datalist id="mounts">
+	<option>Contax/Yashica</option>
+	<option>M42</option>
+</datalist>
+</section>
+
+<section id="lenses">
+<h1>Lenses</h1>
+<ul>
+</ul>
+
+<form>
+	<label for="lens-name">Name:</label>
+	<input id="lens-name" required>
+	<label for="lens-length">Focal length:</label>
+	<span><input id="lens-length" required pattern="[0-9-]+">mm</span>
+	<label for="lens-aperture">Aperture:</label>
+	<span>ƒ/<input id="lens-aperture" required pattern="[0-9.-]+"></span>
+	<label for="lens-mount">Mount:</label>
+	<input id="lens-mount" list="mounts" required>
+	<button type="button" onclick="addLens()">Add</button>
+</form>
+</section>
+
+<script>
+let bodies = JSON.parse(localStorage.getItem("bodies")) || [];
+let lenses = JSON.parse(localStorage.getItem("lenses")) || [];
+let rolls = JSON.parse(localStorage.getItem("rolls")) || {};
+let trips = JSON.parse(localStorage.getItem("trips")) || [];
+let nextId = +localStorage.getItem("nextId") || 1;
+
+document.getElementById("trip-date").valueAsDate = new Date();
+
+function removeButton(onclick) {
+	let remove = document.createElement("a");
+	remove.appendChild(document.createTextNode("⛔"));
+	remove.onclick = onclick;
+	return remove;
+}
+
+function setBodies() {
+	localStorage.setItem("bodies", JSON.stringify(bodies));
+	let ul = document.querySelector("#bodies > ul");
+	let selects = document.querySelectorAll("select.body");
+	ul.innerHTML = "";
+	selects.forEach(select => select.innerHTML = "");
+	for (let [index, body] of bodies.entries()) {
+		let li = document.createElement("li");
+		li.appendChild(document.createTextNode(`
+			${body.name} (${body.mount})
+		`));
+		li.appendChild(removeButton(removeBody.bind(null, index)));
+		ul.appendChild(li);
+		for (let select of selects) {
+			let option = document.createElement("option");
+			option.appendChild(document.createTextNode(body.name));
+			select.appendChild(option);
+		}
+	}
+}
+setBodies();
+
+function endashify(str) {
+	return str.replaceAll("-", "–");
+}
+function lensString(lens) {
+	return `
+		${lens.name}
+		${endashify(lens.focalLength)}mm
+		ƒ/${endashify(lens.aperture)}
+	`.replace(/\s+/g, " ").trim();
+}
+
+function setLenses() {
+	localStorage.setItem("lenses", JSON.stringify(lenses));
+	let ul = document.querySelector("#lenses > ul");
+	ul.innerHTML = "";
+	for (let [index, lens] of lenses.entries()) {
+		let li = document.createElement("li");
+		li.appendChild(document.createTextNode(`
+			${lensString(lens)} (${lens.mount})
+		`));
+		li.appendChild(removeButton(removeLens.bind(null, index)));
+		ul.appendChild(li);
+	}
+}
+setLenses();
+
+function setRolls() {
+	localStorage.setItem("rolls", JSON.stringify(rolls));
+	let ul = document.querySelector("#rolls > ul");
+	ul.innerHTML = "";
+	for (body in rolls) {
+		let roll = rolls[body];
+		let li = document.createElement("li");
+		li.appendChild(document.createTextNode(`
+			${body}: ${roll.film} (${roll.used}/${roll.exposures})
+		`));
+		if (roll.used == roll.exposures) {
+			li.style.textDecoration = "line-through";
+		}
+		ul.appendChild(li);
+	}
+}
+setRolls();
+
+function setTrips() {
+	localStorage.setItem("trips", JSON.stringify(trips));
+	let ul = document.querySelector("#trips > ul");
+	ul.innerHTML = "";
+	let tripsByRoll = Object.groupBy(trips, trip => trip.rollId);
+	for (let rollId = nextId - 1; rollId > 0; --rollId) {
+		let rollTrips = tripsByRoll[rollId];
+		if (!rollTrips) continue;
+		let rollLi = document.createElement("li");
+		let rollB = document.createElement("b");
+		rollB.appendChild(document.createTextNode(rollTrips[0].film));
+		rollLi.appendChild(rollB);
+		rollLi.appendChild(document.createTextNode(` (${rollTrips[0].body})`));
+		let body = bodies.find(body => body.name == rollTrips[0].body);
+		let rollUl = document.createElement("ul");
+		for (let [index, trip] of rollTrips.entries()) {
+			let li = document.createElement("li");
+			let b = document.createElement("b");
+			b.appendChild(document.createTextNode(trip.date));
+			li.appendChild(b);
+			li.appendChild(document.createTextNode(
+				`: ${trip.firstExposure}–${trip.lastExposure}`
+			));
+			if (
+				body.mount != body.name &&
+				(!index || trip.lens != rollTrips[index-1].lens)
+			) {
+				li.appendChild(document.createElement("br"));
+				li.appendChild(document.createTextNode(trip.lens));
+			}
+			if (trip.note) {
+				li.appendChild(document.createElement("br"));
+				li.appendChild(document.createTextNode(`“${trip.note}”`));
+			}
+			rollUl.appendChild(li);
+		}
+		rollLi.appendChild(rollUl);
+		ul.appendChild(rollLi);
+	}
+}
+setTrips();
+
+function setTripBody() {
+	let bodyName = document.getElementById("trip-body").value;
+	let body = bodies.find(body => body.name == bodyName);
+	let select = document.getElementById("trip-lens");
+	select.innerHTML = "";
+	for (lens of lenses.filter(lens => lens.mount == body.mount)) {
+		let option = document.createElement("option");
+		option.appendChild(document.createTextNode(lensString(lens)));
+		select.appendChild(option);
+	}
+	let lastTrip = trips.findLast(trip => trip.body == bodyName);
+	if (lastTrip) {
+		select.value = lastTrip.lens;
+	}
+	let roll = rolls[body.name];
+	if (roll) {
+		document.getElementById("trip-film").value = roll.film;
+		let next = (roll.used > 0 ? roll.used + 1 : roll.used);
+		document.getElementById("trip-first").value = next;
+		document.getElementById("trip-last").value = next;
+	} else {
+		document.getElementById("trip-film").value = "";
+		document.getElementById("trip-first").value = "";
+		document.getElementById("trip-last").value = "";
+	}
+}
+setTripBody();
+
+function clearForm(form) {
+	let inputs = form.querySelectorAll("input");
+	for (input of inputs) {
+		if (input.type == "radio") continue;
+		input.value = null;
+	}
+}
+
+function addBody() {
+	let form = document.querySelector("#bodies > form");
+	if (!form.checkValidity()) return;
+	let name = document.getElementById("body-name").value;
+	let mount = document.getElementById("body-mount").value;
+	bodies.push({ name, mount });
+	setBodies();
+	clearForm(form);
+}
+
+function removeBody(index) {
+	let body = bodies[index];
+	if (!confirm(`Are you sure you want to remove ${body.name}?`)) {
+		return;
+	}
+	bodies.splice(index, 1);
+	delete rolls[body.name];
+	setBodies();
+	setRolls();
+}
+
+function addLens() {
+	let form = document.querySelector("#lenses > form");
+	if (!form.checkValidity()) return;
+	let name = document.getElementById("lens-name").value;
+	let focalLength = document.getElementById("lens-length").value;
+	let aperture = document.getElementById("lens-aperture").value;
+	let mount = document.getElementById("lens-mount").value;
+	lenses.push({ name, focalLength, aperture, mount });
+	setLenses();
+	clearForm(form);
+}
+
+function removeLens(index) {
+	let lens = lenses[index];
+	if (!confirm(`Are you sure you want to remove ${lensString(lens)}?`)) {
+		return;
+	}
+	lenses.splice(index, 1);
+	setLenses();
+	setTripBody();
+}
+
+function loadRoll() {
+	let form = document.querySelector("#rolls > form");
+	if (!form.checkValidity()) return;
+	let body = document.getElementById("roll-body").value;
+	let film = document.getElementById("roll-film").value;
+	let exposures = +new FormData(form).get("roll-exposures");
+	rolls[body] = { id: nextId++, film, exposures, used: 0 };
+	localStorage.setItem("nextId", nextId);
+	setRolls();
+	clearForm(form);
+	setTripBody();
+}
+
+function addTrip() {
+	let form = document.querySelector("#trips > form");
+	if (!form.checkValidity()) return;
+	let date = document.getElementById("trip-date").value;
+	let body = document.getElementById("trip-body").value;
+	let lens = document.getElementById("trip-lens").value;
+	let film = document.getElementById("trip-film").value;
+	let firstExposure = +document.getElementById("trip-first").value;
+	let lastExposure = +document.getElementById("trip-last").value;
+	let note = document.getElementById("trip-note").value;
+	let trip = {
+		date, body, lens, film, rollId: rolls[body].id,
+		firstExposure, lastExposure, note
+	};
+	trips.push(trip);
+	rolls[body].used = lastExposure;
+	setTrips();
+	setRolls();
+	document.getElementById("trip-date").valueAsDate = new Date();
+	document.getElementById("trip-note").value = "";
+	setTripBody();
+}
+
+</script>
diff --git a/www/temp.causal.agency/up.c b/www/temp.causal.agency/up.c
index 4b83b564..561a8901 100644
--- a/www/temp.causal.agency/up.c
+++ b/www/temp.causal.agency/up.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
diff --git a/www/text.causal.agency/037-care.7 b/www/text.causal.agency/037-care.7
index 3fffd778..052a4727 100644
--- a/www/text.causal.agency/037-care.7
+++ b/www/text.causal.agency/037-care.7
@@ -27,6 +27,10 @@ Prices obviously change,
 by which I mean they inevitably go up,
 but I'm gonna give the amounts I paid
 in 2021\(en2022.
+Also if you want more details
+about any of this
+please email me.
+I will be happy to tell you all about it.
 .
 .Ss Medication
 I get HRT through
@@ -65,21 +69,27 @@ for my current prescription
 on the public plan.
 .
 .Ss Hair removal
-I've gotten laser hair removal treatments
-at Dermamode with Audrey.
-They're very nice there.
-The initial consultation was over the phone.
-I paid $1350 for 6 treatments,
-in two installments
-at the first and second appointments,
-plus the ~$200 tax on that
-before the first appointment,
-I think.
-It hasn't gone well for me so far,
-but I'm hoping it will
-now that my testosterone levels
-have dropped.
-I will report back.
+I tried laser hair removal,
+for longer than I should have.
+It was a waste of time and money.
+Do not believe any arguments about
+its convenience over electrolysis.
+.
+.Pp
+I've started getting electrolysis done
+with Dimi.
+Again,
+feel free to email me for contact info.
+He is very good and can do long sessions.
+I really don't find it very painful,
+which I think is partly my own pain tolerance
+and partly good equipment and skill.
+I've also found that taking acetaminophen beforehand
+and dressing warmly to keep my body relaxed help.
+I've paid $85 for hour-long sessions
+and $160 for two-hour sessions.
+I'm still early in treatment,
+but I'm really happy with the results so far!
 .
 .Ss Sex & name change
 The form for this is
@@ -101,7 +111,8 @@ so I made a donation to P10.
 .
 .Pp
 I paid $144 to file mine
-but it's now $148.
+but it's now FREE
+the first time you do it.
 Also $17 to mail it.
 Surprisingly,
 I got an acknowledgment letter
@@ -121,10 +132,12 @@ a week later.
 It takes another 30 days
 to get the certificate of change,
 after which you can
-order a new birth certificate.
-In all it took about 3 months
+order a new birth certificate
+and RAMQ will (slowly) send you a form
+to get a new card.
+In all it took about 4 months
 from when I mailed the application
-to receiving the certificate of change.
+to having ID with my name on it.
 .
 .Ss Therapy
 I'm not seeking therapy
@@ -134,6 +147,17 @@ that's aware of it.
 I'll update this
 if I find one.
 .
+.Ss Piercings
+Ok I know this isn't trans-specific
+but at least for me getting piercings
+was gender-affirming.
+Cuz I got nipple piercings lol.
+Anyway,
+I went to Mauve.
+They're super nice,
+really know what they're doing,
+and their website has lots of info.
+.
 .Sh AUTHORS
 .An june Aq Mt june@causal.agency
 .
diff --git a/www/text.causal.agency/039-apologies.7 b/www/text.causal.agency/039-apologies.7
new file mode 100644
index 00000000..1b15076a
--- /dev/null
+++ b/www/text.causal.agency/039-apologies.7
@@ -0,0 +1,81 @@
+.Dd September 19, 2022
+.Dt APOLOGIES 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm Apologies
+.Nd making them
+.
+.Sh DESCRIPTION
+Apologies are very important to me.
+Unfortunately
+I've only recently realized
+how valuable they are.
+I've tried to think about
+what makes a good apology,
+since it's not something
+I was ever taught.
+This is the advice
+I came up with for myself,
+on how to apologize.
+.
+.Bl -enum
+.It
+Make the apology.
+This is the most important part.
+If you feel guilty
+for something you've done,
+or think you might have hurt someone,
+apologize.
+Even if they don't need an apology,
+saying sorry won't hurt.
+And start with that.
+Literally say
+.Dq I'm sorry .
+Sometimes people forget that.
+.Pp
+On the other side,
+if you've been hurt by someone,
+and you trust them,
+let them know.
+Give them a chance to apologize.
+People don't always realize
+they've made a mistake.
+.
+.It
+Explain what you did wrong.
+I think it's important
+for the other person
+to know you understand
+how you've messed up.
+Really think about this!
+It's what will help you learn.
+If you know you've hurt someone
+but you're not sure why,
+you can try asking them.
+Take their answer seriously.
+.
+.It
+Don't make excuses.
+Do not talk about yourself.
+Don't even mention
+how you were feeling stressed that day,
+or whatever.
+It's not relevant.
+We all make mistakes,
+we all have bad days.
+.
+.It
+Commit to doing better.
+Try to learn from your mistakes.
+Say it won't happen again.
+Literally say
+.Dq I won't do that again .
+And then try your hardest to make that true.
+An apology is a commitment,
+not something you're done with
+once you've said it.
+.El
+.
+.Sh AUTHORS
+.An june Aq Mt june@causal.agency
diff --git a/www/text.causal.agency/040-sound-memory.7 b/www/text.causal.agency/040-sound-memory.7
new file mode 100644
index 00000000..c995de08
--- /dev/null
+++ b/www/text.causal.agency/040-sound-memory.7
@@ -0,0 +1,165 @@
+.Dd November 14, 2022
+.Dt SOUND-MEMORY 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm Sound Memory
+.Nd associations
+.
+.Sh DESCRIPTION
+.Ss Talking Heads \(em "Remain In Light"
+The first time I gave this album a serious listen
+was when I was going for several-hour walks
+at 4 in the morning in,
+I think,
+fall 2020.
+I would stay up all night,
+go out walking at 4am
+for a couple hours,
+come home,
+eat
+.Dq breakfast
+and go to sleep.
+I listened to this album
+walking on completely empty
+big city streets
+in the dark.
+.
+.Ss Buffy Sainte-Marie \(em Up Where We Belong
+I started listening to this album
+after hearing it many mornings
+walking into the cafe on my block
+back in 2019.
+I could tell Vincent was working
+if I heard this when I opened the door.
+.
+.Ss Molasses \(em Trilogie: Toil & Peaceful Life
+I listened to this when I had 8am classes
+in CEGEP.
+In particular my first semester philosophy course,
+which was in the forum.
+I usually got there even earlier
+because of how the bus schedules worked out.
+There was another girl in my class,
+who I always sat next to,
+who also got there early,
+but we never spoke outside of class.
+.
+.Ss Arcade Fire \(em Funeral
+This album just feels like walking outside
+in fresh snow in early winter,
+you know?
+.
+.Ss Molasses \(em Trouble at Jinx Hotel
+I listened to this when I was looking for an apartment.
+I specifically remember listening to it
+walking down Clark toward my new place
+to pick up my keys.
+.
+.Ss Arcade Fire \(em Neon Bible
+The song
+.Dq "No Cars Go"
+is strongly associated for me
+with my earliest gender feelings.
+It's how I date when I first
+started to feel like something was wrong.
+The Suburbs was released in 2010,
+so I was probably listening to Neon Bible
+in 2011.
+Ten years between that
+and coming out.
+.
+.Ss "Do Make Say Think" \(em "You You're a History In Rust"
+I remember hearing
+.Dq "A Tender History In Rust"
+for the first time
+at the office of my first job.
+Me and my coworkers stayed late,
+probably on a Friday night,
+drinking free tech startup booze.
+.
+.Ss mewithoutYou \(em It's All Crazy! It's All False! It's All a Dream! It's Alright
+I exclusively listened to this album
+on a high school trip to Europe.
+Every morning when we got on the bus,
+I heard
+.Dq Every Thought a Thought of You
+and every night before bed
+I listened to
+.Dq The King Beetle on a Coconut Estate .
+.
+.Ss Arcade Fire \(em The Suburbs
+I listened to this album a tonne
+when I was playing
+Minecraft and Urban Terror
+with my online friends
+while I was in high school.
+In particular I remember
+a backyard shed World of Padman map
+and the apartments Minecraft world.
+.
+.Ss Arcade Fire \(em Reflektor
+I associate
+.Dq Afterlife
+with the walk between Laurier metro
+and my first job,
+in the winter.
+Must've just been how the timing worked out
+with my commute at the time.
+.
+.Ss Swans \(em To Be Kind
+I listened to this on one of my playthroughs
+of Half-Life 2.
+In particular I associate
+.Dq Bring the Sun / Toussaint L'Ouverture
+with the Water Hazard chapter.
+.
+.Ss Wrekmeister Harmonies \(em Light Falls
+For a while I put this on whenever I
+left my apartment to go somewhere
+and it was already dark,
+so probably winter.
+.
+.Ss St. Vincent \(em MASSEDUCTION
+This,
+along with the next one,
+I think were all I listened to
+on a family vacation
+to Quebec City and New Brunswick
+some years ago.
+.
+.Ss SOPHIE \(em Oil of Every Pearl's Un-Insides
+Many hours on the road
+on that family vacation.
+Two albums on repeat.
+.
+.Ss Julia Holter \(em Aviary
+This is another album
+I listened to when I was taking
+walks at 4am.
+I wasn't in a good place.
+Yet.
+.
+.Ss Beep Test \(em Laugh Track
+A tape from the first act
+at one of my favourite shows
+I've ever been to,
+at La Sotterenea
+in Suoni 2019.
+I wish I had been out already.
+.
+.Ss The Armed \(em Only Love
+The third of the albums I listened to
+on those dark walks.
+I listened to it loud,
+this album's mixing needs it.
+.
+.Ss Eliza Kavtion \(em The Rez That Summer
+A favourite local artist.
+I remember vividly the first time
+I heard her play,
+opening for Wrekmeister Harmonies
+at La Vitrola in 2018.
+.
+.Sh AUTHORS
+.An june Aq Mt june@causal.agency
diff --git a/www/text.causal.agency/041-albums-2022.7 b/www/text.causal.agency/041-albums-2022.7
new file mode 100644
index 00000000..48bd3c3d
--- /dev/null
+++ b/www/text.causal.agency/041-albums-2022.7
@@ -0,0 +1,185 @@
+.Dd December 21, 2022
+.Dt ALBUMS-2022 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm albums 2022
+.Nd review
+.
+.Sh DESCRIPTION
+it's the year-end review
+of albums I listened to.
+same as last year,
+I added any albums I got into
+this year to a playlist.
+I've actually done that
+every year since 2018.
+maybe I'll review
+those old playlists some time.
+.
+.Ss ZHAOZE \(em SUMMER INSECTS TALK ABOUT ICE (2021)
+it's a five-and-a-half-minute album!
+you can loop it however long you want.
+it's really lovely.
+.Pp
+favourite track:
+ON HORSEBACK, TO FARAWAY
+.
+.Ss KATE BUSH \(em HOUNDS OF LOVE (1985)
+first of all I do not watch that one show.
+I've known that track for a while actually.
+I mean I probably first heard the CHROMATICS cover.
+but anyway,
+I think someone mentioned this album
+on IRC at just the right time
+and I put it on.
+the second half really shines tbh.
+love a concept album.
+.Pp
+favourite tracks:
+RUNNING UP THAT HILL,
+HOUNDS OF LOVE,
+AND DREAM OF SHEEP,
+WATCHING YOU WITHOUT ME,
+THE MORNING FOG.
+.
+.Ss GODSPEED YOU! BLACK EMPEROR \(em ALL LIGHTS FUCKED ON THE HAIRY AMP DROOLING (1994)
+didn't expect to hear this probably ever.
+still wild that it finally got uploaded.
+and to be honest I'm a little mad
+that it's actually good.
+like yeah it's not a godspeed album
+but it holds up as a tape on its own.
+it's the kind of shit I listen to.
+also can't believe some people
+still thought it was fake.
+like have you not heard
+any other efrim menuck projects?
+.Pp
+favourite tracks:
+$13.13,
+DIMINISHING SHINE,
+DADMOMDADDY,
+333 FRAMES PER SECOND,
+ALL ANGELS GONE.
+.
+.Ss BLACK DRESSES \(em FORGET YOUR OWN FACE (2022)
+woops I think I only listened to this like twice.
+will need to revisit it later for sure.
+I'll like it.
+.
+.Ss BACKXWASH \(em I LIE HERE BURIED WITH MY RINGS AND MY DRESSES (2021)
+only got into this album
+after hearing it live this summer.
+was the first show I went to in years
+and it was really fucking good.
+gotta listen to this shit loud.
+sampling godspeed for a beat fucks.
+honestly back to back bangers.
+.Pp
+favourite tracks:
+I LIE HERE BURIED WITH MY RINGS AND MY DRESSES,
+TERROR PACKETS,
+SONG OF SINNERS,
+BURN TO ASHES.
+.
+.Ss PHILIP GLASS ENSEMBLE \(em EINSTEIN ON THE BEACH (1979)
+actually just the knee plays
+because I can't be bothered
+listening to all of it.
+and I'm embarrassed by how much
+I enjoy this avant-garde bullshit.
+like ok just sing repeating numbers at me
+and my brain is happy.
+what is this?
+my kink?
+anyway I also have kind of an obsession
+with the
+.Dq story of love
+in knee 5.
+I fucking hate it.
+but it's delivered so well.
+and that violin though!
+.Pp
+favourite tracks:
+KNEE 1,
+KNEE 5.
+.
+.Ss KANYE WEST \(em YEEZUS (2013)
+ok look I listened to this
+before recent events.
+what the fuck.
+it's a really good album though?
+pretty sure I listened to it
+because bound 2 kept getting in my head,
+because of that minecraft parody parody
+wayne did ages ago.
+.Pp
+favourite tracks:
+BLACK SKINHEAD,
+HOLD MY LIQUOR,
+BLOOD ON THE LEAVES,
+BOUND 2.
+.
+.Ss FLYING RACCOON SUIT \(em AFTERGLOW (2021)
+I've listened to the whole album
+a few times
+but I'm mostly just here
+for the title track.
+this also happened to be
+dropped in IRC at just the right time.
+good ska-punk-type shit.
+and I like lisps ok.
+.Pp
+favourite track:
+AFTERGLOW.
+.
+.Ss RAMSHACKLE GLORY \(em LIVE THE DREAM (2011)
+one of those albums
+I don't know why I took so long
+to get to.
+I've been listening to johnny hobo
+since I was like in high school.
+ramshackle is a little more hopeful
+and I love that.
+your heart is a muscle the size of your fist.
+keep on loving.
+keep on fighting.
+.Pp
+favourite tracks:
+WE ARE ALL COMPOST IN TRAINING,
+NEVER COMING HOME,
+YOUR HEART IS A MUSCLE THE SIZE OF YOUR FIST.
+.
+.Ss LES RALLIZES D\('ENUD\('ES \(em THE OZ TAPES (2022)
+a pleasant surprise in someone's playlist.
+lately I've been listening to this
+in the metro to or from electrolysis.
+it's good listening for that.
+bold to have two versions
+of the same 24-minute song
+on the same release.
+.Pp
+favourite tracks:
+A SHADOW ON OUR JOY,
+THE LAST ONE_1970 (ver.2).
+.
+.Ss LINGUA IGNOTA \(em SINNER GET READY (2021)
+another I'm only getting into
+after hearing it live.
+just last sunday actually.
+was a good show.
+people will go wild
+to hear a cover live for real.
+.Pp
+favourite tracks:
+I WHO BEND THE TALL GRASSES,
+PENNSYLVANIA FURNACE,
+PERPETUAL FLAME OF CENTRALIA.
+.
+.Sh AUTHORS
+.An june Aq Mt june@causal.agency
+.Pp
+I started writing this
+before I saw LINGUA IGNOTA.
+good thing I waited.
diff --git a/www/text.causal.agency/042-comfort-music.7 b/www/text.causal.agency/042-comfort-music.7
new file mode 100644
index 00000000..445e04c3
--- /dev/null
+++ b/www/text.causal.agency/042-comfort-music.7
@@ -0,0 +1,62 @@
+.Dd February 23, 2024
+.Dt COMFORT-MUSIC 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm comfort music
+.Nd feel better
+.
+.Sh DESCRIPTION
+it's been a while.
+and I'm on almost no sleep
+and haven't eaten a real meal
+since noon.
+which is a state I've written
+at least a couple posts in before,
+so what better time
+to return to what has apparently
+become this blog's format:
+lists of some music I like.
+.
+.Pp
+this is a list of music that comforts me.
+.
+.Bl -bullet
+.It
+knee play 5, from einstein on the beach.
+I like the organ and the counting and the cadence of the story.
+.It
+low \(em words.
+and I'm tired.
+.It
+godspeed you! black emperor \(em storm.
+this is like my original comfort music.
+been listening to it since I was teenage.
+the grooves are worn deep in my mind.
+.It
+set fire to flames \(em love song for 15 ontario (w/ singing police car).
+I like how it ends.
+.It
+va, from the beginner's guide.
+I think that's the whole point.
+though maybe it's too sad
+to be truly comforting.
+.It
+undertale, from undertale.
+what can I say?
+.It
+wrekmeister harmonies \(em covered in blood from invisible wounds.
+I find quite a bit of the album comforting really.
+I'm picking this one because I like the cadence
+of the lyrics.
+.It
+lingua ignota \(em pennsylvania furnace and perpetual flame of centralia.
+these are really my go to in recent times.
+I like waiting for the next line.
+.El
+.
+.Sh AUTHORS
+.An june Aq Mt june@causal.agency
+.Pp
+I don't think I've said anything
+very interesting here.
diff --git a/www/text.causal.agency/043-little-blessings.7 b/www/text.causal.agency/043-little-blessings.7
new file mode 100644
index 00000000..957c6289
--- /dev/null
+++ b/www/text.causal.agency/043-little-blessings.7
@@ -0,0 +1,78 @@
+.Dd March 24, 2024
+.Dt LITTLE-BLESSINGS 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm little blessings
+.Nd life's
+.
+.Sh DESCRIPTION
+today I went out to go around.
+run some errands and do some shopping.
+along the way I was given
+several of life's little blessings.
+.
+.Pp
+while walking on ste-cath
+between berri and complexe desjardins,
+there was a somewhat disheveled man
+walking in the same direction and singing.
+he had a beautiful voice.
+he was singing a sad song in french,
+and he sung it well and enunciated every word.
+.
+.Pp
+in the mcdonald's at complexe desjardins,
+while waiting for my order,
+there were what appeared to be
+a teenager and her younger brother,
+who must have been
+looking at the display of
+current happy meal toys.
+the teenager was playing smash or pass,
+to the amusement of the younger one.
+they got ice cream
+and ate it across the room from me downstairs.
+.
+.Pp
+later,
+taking the 24 home from atwater
+carrying my new vacuum cleaner,
+the bus got lost.
+I think the driver missed the stop
+and tried to compensate
+by turning north onto peel
+and stopping there.
+but then he had to keep going up peel.
+he turned right onto docteur-penfield,
+which just brings you further up the mountain.
+when it met des pins,
+he turned left and pulled over,
+asking for guidance over the radio.
+we got moving again,
+back towards peel.
+that's how I ended up
+on a 24
+.Dq sherbrooke
+east,
+facing west on des pins.
+it was actually quite scenic.
+and amusing.
+I was in no rush.
+.
+.Pp
+after getting back onto sherbrooke,
+the bus had to take another detour,
+this one planned.
+so my ride on the 24,
+which normally only drives on sherbrooke,
+ended up going on peel,
+docteur-penfield,
+des pins,
+de bleury,
+ren\('e-l\('evesque
+and saint-laurent.
+it was a very exciting bus trip.
+.
+.Sh AUTHORS
+.An june Aq Mt june@causal.agency
diff --git a/www/text.causal.agency/044-film-review.7 b/www/text.causal.agency/044-film-review.7
new file mode 100644
index 00000000..8e8feca8
--- /dev/null
+++ b/www/text.causal.agency/044-film-review.7
@@ -0,0 +1,208 @@
+.Dd October 12, 2024
+.Dt FILM-REVIEW 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm film review
+.Nd stock, that is
+.
+.Sh DESCRIPTION
+this summer I got really into analog photography.
+I've tried out a bunch of different film stocks,
+thanks to the local photo lab,
+and I've
+.Em developed
+(pun intended)
+some preferences.
+here they are.
+.
+.Sh BLACK & WHITE
+.Bl -enum
+.It
+Ilford FP4+ (ISO 125, United Kingdom)
+.Pp
+definitely my favourite b&w film.
+I love the fine grain and contrast
+with good shadow detail.
+really just exactly what I want
+out of a b&w film I think.
+ISO 125 is quite generous for what it is,
+but it's still best suited for sunny days.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-09-29/
+.
+.It
+Fomapan Creative (ISO 200, Czech Republic)
+.Pp
+I've only shot one roll of this so far,
+but I really like the balance it strikes
+between fine grain and high speed.
+it just seems like a good go-to film
+for what I like to do with b&w photography,
+given the extra flexibility over FP4.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-09-14/
+.
+.It
+Ferrania P30 (ISO 80, Italy)
+.Pp
+another that I've only shot one roll of,
+but I really like the results.
+obviously it swings in the other direction
+in terms of film sensitivity,
+but more importantly
+it has a distinctive look.
+that's harder in b&w than it is in colour!
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-10-05/
+.
+.It
+Ilford Delta 100 (United Kingdom)
+.Pp
+as far as I'm concerned this is just more expensive FP4.
+it certainly looks good
+but I'd rather save the couple extra dollars.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-09-22/
+.
+.It
+Ilford HP5+ (ISO 400, United Kingdom)
+.Pp
+it's like, ok.
+more grainy than I'd like,
+but that's to be expected of high speed.
+my real problem with it
+is the lack of contrast.
+maybe I should only be shooting it pushed,
+but I don't want to pay the extra fee
+to have my local photo lab do that.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-09-07/
+.
+.It
+Fomapan Action (ISO 400, Czech Republic)
+.Pp
+I almost wonder if something went wrong
+either in shooting or processing
+the one roll of this I shot.
+everything came out very low contrast.
+.Pp
+sample:
+I didn't end up uploading any.
+.El
+.
+.Sh COLOUR
+.Bl -enum
+.It
+Shanghai Color (ISO 400, China)
+.Pp
+I love the desaturated colours
+and the grain on this.
+I guess I like fine grain in b&w
+and coarse grain in colour.
+I think this is well suited
+to the subjects I like to photograph,
+like old brick buildings,
+but it also does nature quite nicely.
+I think this will be a good one to capture fall with.
+.Pp
+ok so this is almost certainly repackaged
+Wolfen Color NC500
+(made in germany).
+but the thing is,
+shanghai does a better job packaging it.
+they use real metal cassettes
+and add film edge markings.
+and their box design is way nicer.
+and on top of THAT,
+my local photo lab
+sells it for cheaper than NC500.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-09-22/
+.
+.It
+Harman Phoenix (ISO 200, United Kingdom)
+.Pp
+phoenix is a fun film!
+the lack of yellow filter
+and anti-halation layer
+can produce some neat effects.
+in the right conditions
+it also sometimes looks exceedingly normal.
+but it also sometimes just...
+doesn't work well.
+underexposed areas can get really bad.
+apparently it can be better to shoot it at ISO 100.
+I should give that a try,
+or just be more diligent with
+how I'm metering.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-08-10/
+.
+.It
+CineStill 800T (USA?)
+.Pp
+I can't really say much about this yet.
+I don't have much experience with indoor photography.
+the lack of anti-halation layer
+does tend to make lights look sinister as hell, though.
+I'll probably shoot
+one of the cheaper repackagings
+of ISO 800 cinema film
+in the future.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-10-06/
+.
+.It
+Film Washi
+.Dq X
+(ISO 100, France)
+.Pp
+this is mostly pretty normal film
+without a yellow filter.
+not much to say about it.
+I'd be more interested to try washi's
+other repackaged b&w technical films,
+but I think I missed them being in stock here.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-08-23/
+.
+.It
+Fujifilm 400 (Japan?)
+.Pp
+I shot my two first ever rolls on this.
+they were surprisingly good!
+the scans did the film dirty though.
+that was before I found the good photo lab.
+.
+.It
+Kodak Gold (ISO 200, USA)
+.Pp
+ok so this is a cheap film, right?
+but it's too damn good.
+fine grain, accurate colour.
+it looks like digital to me,
+and that's not what I want.
+even fuji has a little more character to it than this.
+puts me off kodak.
+.Pp
+sample:
+.Lk https://photo.causal.agency/2024-07-01/
+.El
+.
+.Sh AUTHORS
+.An Juniper Aq Mt june@causal.agency
+.
+.Pp
+if you have suggestions
+for film stocks I should try,
+send me an email.
diff --git a/www/text.causal.agency/Makefile b/www/text.causal.agency/Makefile
index c5555274..6b1bd02f 100644
--- a/www/text.causal.agency/Makefile
+++ b/www/text.causal.agency/Makefile
@@ -38,15 +38,25 @@ TXTS += 035-addendum-2021.txt
 TXTS += 036-compassion.txt
 TXTS += 037-care.txt
 TXTS += 038-agency.txt
+TXTS += 039-apologies.txt
+TXTS += 040-sound-memory.txt
+TXTS += 041-albums-2022.txt
+TXTS += 042-comfort-music.txt
+TXTS += 043-little-blessings.txt
+TXTS += 044-film-review.txt
 
 all: colb ${TXTS}
 
-.SUFFIXES: .7 .txt
+.SUFFIXES: .7 .fmt .txt
 
 .7.txt:
 	mandoc -T utf8 $< | ./colb > $@
 	touch -m -r $< $@
 
+.fmt.txt:
+	fmt $< | sed '1,/^$$/d' > $@
+	touch -m -r $< $@
+
 feed.atom: feed.sh colb ${TXTS}
 	sh feed.sh > feed.atom
 
diff --git a/www/text.causal.agency/feed.sh b/www/text.causal.agency/feed.sh
index 668046ef..71bbf662 100644
--- a/www/text.causal.agency/feed.sh
+++ b/www/text.causal.agency/feed.sh
@@ -27,6 +27,7 @@ set -- *.txt
 shift $(( $# - 20 ))
 for txt; do
 	entry="${txt%.txt}.7"
+	test -f "$entry" || entry="${txt%.txt}.fmt"
 	date=$(grep '^[.]Dd' "$entry" | cut -c 5-)
 	title=$(grep -m 1 '^[.]Nm' "$entry" | cut -c 5- | encode)
 	summary=$(grep '^[.]Nd' "$entry" | cut -c 5- | encode)