field notes


  • Pilea peperomioides (UFO)
  • Epipremmum aureum (Golden, Neon Pothos)
  • Philodendron hederaceu (Heart, Brasil), Hastatum (Silv. Sword)
  • Ficus Benjamina, Elastica (rubber)
  • Syngonium podophyllum
  • Spathiphyllum (peace lily)
  • Diffenbachia
  • Begonia Rex, Maculata (Polka dot)
  • Sedum morganianum (Donkey tail)
  • Ceropegia woodii (String Hearts)
  • Impatiens
  • Olive tree
  • Dichondra repens
  • Strelitzia Nicolai (Bird of Paradise)
  • Dracena fragrans (Happy plant)
  • Alocasia frydek, amazonica
  • Euphorbia Trigona, Milli

  • Begonia Rex 'Escargo"
  • Dioscorea elephantipes


Adult soft drinks :)

There’s also a couple of non-beers in here…

  • Coopers - PA, XPA, SA
  • Rover - Henty St. Ale
  • Burleigh - Mid-tide
  • Garage Project - Beer, Golden Path IPA, Baltic Porter
  • Hawkesbury - PA
  • Initial - XPA, IPA
  • James Squire - 150PA
  • Little Creatures - PA, XPA, Squeaky Clean IPA
  • 4 Pines - PA
  • Young Henrys - Newtowner PA, IPA, Porter
  • Gage Roads - Pipe Dreams
  • Kirin - Megumi, Ichiban
  • Balter - XPA, Hazy IPA, IPA
  • Botany - Tropical A
  • Colonial - XPA, PA, Sour, Porter
  • White Rabbit - Golden Sour, Dark Ale
  • Culture House - Raspberry Sour
  • Zytho - PA, Hemp IPA, IPA, Stout
  • Black Hops - Hop Swap IPA
  • Atomic - PA
  • John Boston - IPA, XPA
  • Colossal - East Coast IPA, West Coast IPA
  • Hope - XPA
  • Blackmans - Incredible Haze DIPA, Funky Town IPA
  • Hargrave Hills - Uninterrupted Prosperity NEIPA
  • Wolf of the willows - Pup APA
  • Akasha - Canada Bay XPA, Hopsmith IPA, C9 Hazy IPA
  • Deeds - Juice Train DNEIPA
  • Algorithm - PA
  • Tinnies - Pacific Ale, XPA, IPA
  • Black & Hops - PA
  • Fixation - Little Ray IPA, Gin Sour, Easy St IPA, Maple Stout, Fix DIPA
  • Moon Dog - Old Mate PA, Fizzer
  • Hopsters - IPA, NEIPA (w/ Frenchies)
  • Molly Rose - Indian Brown Ale, Skylight IPA
  • Grifter - PA, Big Sur IPA, Dark Larger
  • Willy the Boatman - Crazy Ivan IPA
  • Rocks - PA
  • Philter - XPA, Red Ale, Caribbean Stout
  • White Bay - Ken Oath NEIPA, Pils, Sequoia WC DIPA
  • Batch - IPA
  • Yullis - Black IPA
  • Mountain Culture - PA, Me Time NEIPA, Alpine Starter DIPA
  • Pirate Life - Black IPA , Wheat PA
  • Bridge Road - New Sky v1 IPA
  • Echigo - Koshikari
  • Weihenstephaner - Original Helles, Pils
  • Murrays - PA


I prefer working with 5mm grid paper, but am looking into dotted grid paper.

In the past I’ve taken notes/sketched in A5 unruled spiral notebooks, which are cheap and easy to remove pages. I’ve also used spiral grid notebooks, although I’ve only come across these in A4.

I have a MIDORI brand notebook which I very much enjoy.

At sime point I'll end up with a Hipster PDA

Making notebooks #

Stack ~10 centre-creased sheets of paper and either staple or sew down the middle. This will make a 40 page bundle (since each sheet will be halfed).

Then you can sew 40 page bundles together to make a bigger book.

A slip on cover can be made from some light card, however you’ll want to go up a size from your sheets, since you’ll want to slip it into the first and last pages.

To make an ~A5 size notebook you’ll want to fold A4 pages in half.


Zero-initialization #

From the standard:

If there are fewer initializers in a brace-enclosed list than there

are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration

C99 Standard Draft,

Section 6.7.8, Point 21

Looking at point 10 just above that we will see that this means

initialized to NULL/0. This gives way to the common practive of doing something like

int f(int k) { struct myStruct = { 0 }; // ... }

Which gives us a nicely zero-initialized variable on the stack (same

applies for arrays, etc.).

This ruling also applies if you just wanted to initialize one or two

members to non-zero.

Enums for better arrays. #

Here’s a trick I learnt from sfeed,

you can use an enum to name the members of some data stored in an array. As a bonus you can add a COUNT member which will be the size of your array to read the whole blob into it.

enum {
    PKT_HEADER = 0,

// …
    unsigned char data[PACKET_COUNT];
    fread(data, sizeof(*data), PACKET_COUNT, fp);
    printf(“Byte 1: %hhu\n”, data[PKT_BYTE1]);

I could see people at work complaining this is horrible design, but I

quite like it :)

Better sizeof #

Taking a look at the snippet above, you might’ve also noticed that the size parameter that I pass to fread(3) is coming from the size of

whatever our variable points to indirectly.

This means we don’t have to copy-paste the data type into the sizeof

and get a codebase that would work if we started using a different-sized data type (obviously in this example it wouldn’t make a tonne of sense for that to happen – but I think it is an improvement here anyway).

ASAN + LeakSanitizer #

The address sanitizer will make debugging segfaults actually viable

(-fsanitize=address), and should absolutely be enabled during development.

The leak sanitizer will also catch a lot of memory leaks (direct &

indirect) and will probably encourage you to fix them now instead of later (which you should). In my version of gcc, enabling ASAN also turns on LSAN.

Assert often #

This isn’t really a C-specific piece of advice but I think it’s something

that most people overlook – assertions are like breakpoints baked into your program to stop you doing stupid shit. This is especially helpful when the language doesn’t throw exceptions when you do said stupid shit.

I also really like using them if I’m stubbing out functions – leave an assert(0 && "TODO: Implement this thing"), and that way you can safely

forget about that stub until you need it.


2023 #

  • Frog Detective 3: Corruption at Cowboy County

2022 #

  • Uriel's Chasm

2021 #

  • MaryPark St. (2/5)
  • Undertale (4/5)
  • Xoo: Xeno Xafari (4/5)
  • Magic Wand (4/5)
  • Hell (3.5/5)
  • Critters For Sale: SNAKE (5/5)
  • Water Womb World (4/5)
  • Gorogoa (5/5)
  • The Odd Neon Void (2/5)
  • LiEat (3.5/5)
  • Buddy Simulator 1995 (4/5)
  • Critters For Sale (4.5/5)
  • A Date in the Park (4/5)
  • My Hole is a Mouth of Dirt
  • Dujanah
  • The Endless Empty (3.5/5)
  • Ohr (3.5/5)
  • Dandelion (3.5/5)
  • Space Funeral (4.5/5)
  • Milk inside a bag of milk inside a bag of milk

2020 #

  • Ghostdream (2.5/5)
  • RE: Get To Schol On Time (5/5)
  • OK/NORMAL (2.5/5)
  • Mothlight (4/5)
  • Moon: Remix RPG (4/5)
  • Donut County (4/5)
  • Wide Ocean Big Jacket (4.5/5)
  • Geezer Gus: The Meteorite Motel (4/5)
  • OFF (4/5)
  • Alien Squatter (5/5)
  • Winter Novel (2.5/5)
  • Hotel Sowls (3/5)
  • Monster Garden (3/5)
  • A Short Hike (5/5)
  • LISA: The Joyful (3.5/5)
  • LISA: The Painful (5/5)
  • Animal Crossing: New Horizons (5/5)
  • Rain City (2.5/5)
  • Wurroom (3.5/5)
  • YIIK: A Postmodern RPG (2/5)
  • Archillion Saga (2/5)
  • Pikuniku (4.5/5)
  • samurai_jazz (3/5)
  • A Space for the Unbound - Prologue (4/5)
  • Bloody Walls (2.5/5)
  • Rainyday (4/5)
  • Hotline Miami (5/5)
  • DON'T GIVE UP: A Cynical Tale (3.5/5)
  • You Have to Win the Game (5/5)
  • The Ship Single Player (3/5)

2018~2019 #

  • Mafia II (5/5)
  • The Stanley Parable (5/5)
  • Spy Fox 2 "Some Assembly Required" (5/5)
  • Sorry, James (3.5/5)
  • Deep Space Waifu (4/5)
  • Foto Flash (3/5)
  • There's Poop in my Soup (lovepoop/5)
  • Pony Island (5/5)
  • Off Peak (4.5/5)
  • The Norwood Suite (4/5)
  • Virginia (3/5)
  • Bucket Detective (4/5)
  • The Darkness II (4/5)
  • Baobabs Mausoleum Ep. 1... (4/5)
  • Midnight Ultra (4/5)
  • Cleansuit (3.5/5)
  • Squidlit (4/5)
  • Foto Flash 2 (1/5)
  • The Haunted Island, a Frog Detective Game (4.5/5)
  • VVVVVV (5/5)
  • The Hex (3.5/5)
  • Thomas Was Alone (3.5/5)
  • Super Win the Game (4.5/5)
  • Tick Tock Isle (2.5/5)
  • Qora (2.5/5)
  • Murder at the Residence Gudul (4/5)
  • Sacrifices Must Be Made (5/5)
  • Anodyne (5/5)
  • Frog Detective 2: The Case of the Invisible Wizard (4/5)
  • Poopy Philosophy (lovepoop/5)
  • Macbat 64 (3.5/5)
  • Football Game (3/5)



  • Ballard - Crash
  • Dostoevsky - Crime and Punishment
  • Kerouac - On the road
  • Garcia Marquez - 100 years of solitude
  • Allende - House of spirits
  • Gibson - Count Zero
  • Kafka - Amerika
  • Bowles - Sheltering Sky


Draft proposal for some very important extensions to c-lang

  • new/free keywords
  • REPL
  • #include <http.server>\nhttp_serve();
  • Namespacing
  • """Lambda functions"""
  • unsafe block

TBA at at some point never


N.B.: I am primarily familiar with Microsoft's dialect (regrettably).

Documented here are some crimes against humanity.

Generating JSON #

No fancy JSON functions in my version of SQL Server :(

CREATE TYPE [dbo].[JsonifiableData] AS TABLE(
	[JsonPath] [varchar](max) NOT NULL,
	[JsonValue] [varchar](max) NULL,
	[JsonType] [varchar](max) NOT NULL DEFAULT ('string')

CREATE FUNCTION [dbo].[fn_JsonifyData] (@data JsonifiableData READONLY)
	DECLARE @accumulator JsonifiableData

	-- "Base case", there is no subpath (ie. no 'dot's left)
	INSERT INTO @accumulator (JsonPath, JsonValue, JsonType)
		CASE JsonType
			WHEN 'string' THEN CONCAT('"', REPLACE(REPLACE(REPLACE(JsonValue, '''', '\'''), CHAR(10), '\n'), CHAR(13), '\r'), '"')
			WHEN 'date' THEN CONCAT('"', FORMAT(CAST(JsonValue AS DATETIME), 'O'), '"')
			WHEN 'array' THEN 'Arrays are not supported (lol)'
			ELSE JsonValue
	FROM @data
	WHERE CHARINDEX('.', JsonPath) = 0
		-- Treat NULL in this table as an "undefined" property, so don't send it.

	/* Recursive case(s), where there is some child paths.
	 * We group on the child path in case there are two things
	 * that should go to the same child object */
	DECLARE curs cursor FOR
		SELECT SUBSTRING(JsonPath, 0, CHARINDEX('.', JsonPath))
		FROM @data	
		GROUP BY SUBSTRING(JsonPath, 0, CHARINDEX('.', JsonPath))
		HAVING SUBSTRING(JsonPath, 0, CHARINDEX('.', JsonPath)) <> ''
	OPEN curs
	DECLARE @childData JsonifiableData

		DELETE FROM @childData
		INSERT INTO @childData
			SUBSTRING(JsonPath, LEN(@path) + 2, LEN(JsonPath)),
		FROM @data
		WHERE CHARINDEX(@path + '.', JsonPath) = 1

		INSERT INTO @accumulator (JsonPath, JsonValue, JsonType)
		VALUES (@path, dbo.fn_JsonifyData(@childData), 'JSON')

	CLOSE curs

	SELECT @result = '{' + dbo.af_String_Agg(CONCAT('"', JsonPath, '": ', JsonValue), ', ') + '}'
	FROM @accumulator

	RETURN @result

I haven't implemented arrays yet because I didn't need them.

Also afStringAgg is a gross custom CLR function since I also didn't have string_agg.

If you don't either you could get away with just setting @result = @result + CONCAT(...)

Helpful kinda-declaritive-y way of converting a wide table into a tall table as required by this function:

DECLARE @tbl JsonifiableData

INSERT INTO @tbl (JsonPath, JsonValue)
FROM someTable
    ('example.nesting.a', someTable.a),
    ('example.nesting.b', someTable.b),
    ('example.c', someTable.c)
) P(JsonPath, JsonValue)
WHERE id = x

Generating Dates #

SELECT DATEFROMPARTS(yearr, monthh, dayy) datee
FROM (VALUES (1900),(1901),(1902),(1903),(1904),(1905),(1906),(1907),(1908),(1909),(1910),(1911),(1912),(1913),(1914),(1915),(1916),(1917),(1918),(1919),(1920),(1921),(1922),(1923),(1924),(1925),(1926),(1927),(1928),(1929),(1930),(1931),(1932),(1933),(1934),(1935),(1936),(1937),(1938),(1939),(1940),(1941),(1942),(1943),(1944),(1945),(1946),(1947),(1948),(1949),(1950),(1951),(1952),(1953),(1954),(1955),(1956),(1957),(1958),(1959),(1960),(1961),(1962),(1963),(1964),(1965),(1966),(1967),(1968),(1969),(1970),(1971),(1972),(1973),(1974),(1975),(1976),(1977),(1978),(1979),(1980),(1981),(1982),(1983),(1984),(1985),(1986),(1987),(1988),(1989),(1990),(1991),(1992),(1993),(1994),(1995),(1996),(1997),(1998),(1999),(2000),(2001),(2002),(2003),(2004),(2005),(2006),(2007),(2008),(2009),(2010),(2011),(2012),(2013),(2014),(2015),(2016),(2017),(2018),(2019),(2020),(2021),(2022),(2023),(2024),(2025),(2026),(2027),(2028),(2029),(2030),(2031),(2032),(2033),(2034),(2035),(2036),(2037),(2038),(2039),(2040),(2041),(2042),(2043),(2044),(2045),(2046),(2047),(2048),(2049),(2050),(2051),(2052),(2053),(2054),(2055),(2056),(2057),(2058),(2059),(2060),(2061),(2062),(2063),(2064),(2065),(2066),(2067),(2068),(2069),(2070),(2071),(2072),(2073),(2074),(2075),(2076),(2077),(2078),(2079),(2080),(2081),(2082),(2083),(2084),(2085),(2086),(2087),(2088),(2089),(2090),(2091),(2092),(2093),(2094),(2095),(2096),(2097),(2098),(2099),(2100)) years(yearr)
CROSS JOIN (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) months(monthh)
JOIN (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31)) days(dayy)
	ON ISDATE(CONCAT(yearr, '-', monthh, '-', dayy)) = 1

Note that I have never actually been able to use this in production because when using it in joins TSQL was somehow doing the DATEFROMPARTS before the ISDATE, causing DATEFROMPARTS to throw :(.

If you need more years seq 1900 2100 | tr '\n' ',' | sed 's/\([0-9]*\),/(\1),/g' ;)

SEE-ALSO: Generate a set or sequence without loops


2023-02-13 #

topics: writing,drawing,art

  • I should've planted this tree 25 years ago
  • Making language say more than words
  • The music in what you want to say
  • Cezanne Houses


Some (sh-)scripts which may or may not be useful.

Service-CLI wrappers #

Adapt this to match whatever shitty service you need

function hamachi {
    pgrep hamachid > /dev/null || (echo "Hamachi is not running, starting..."; sudo systemctl start logmein-hamachi; sleep 1)
    $(which hamachi) "$@"

X11 Backlight #

For some reason most of the OTS solutions (ie. xbacklight) stink and only work sometimes. If you have an exposed device in /sys you can control it from there relatively easily

backlight() {
        max="$(cat /sys/class/backlight/intel_backlight/max_brightness)"
        target="$(echo "($max * ($1 / 100))" | bc -l | cut -d'.' -f1)"
        echo "Setting backlight brightness to $1% ($target)"
        sudo /bin/bash -c "echo '$target' > /sys/class/backlight/intel_backlight/brightness"

OK #

I saw this on someone's blog (sorry, whoever you were!) and thought it was a neat idea. Then I looked at the repo and it was in python for some reason and seemed to do a lot more than it needed, here's my implementation

ok() {
        test -f ".ok" || touch -f ".ok"

        if [ -z "$cmd" ]; then
                nl ./.ok
                return 0

        if ! $(test "$cmd" -eq "$cmd" 2>/dev/null); then
                echo "NOTOK> Expected first argument to be a number!" > /dev/stderr
                return 1

        cmd="$(line "$cmd" < .ok)"

        if [ -z "$cmd" ]; then
                echo "NOTOK> No such command" > /dev/stderr
                return 1

        echo "OK> $cmd"
        eval "$cmd"

Paste & Edit #

One day I'll implement a file-driver for the xclipboard, for now I have this

function pasteAndEdit {
        test -z "$target" && target="$(mktemp)"
        xcp -o | dos2unix > "$target"
        "$EDITOR" "$target"

Oh an xcp is aliased as xclip -selection c



*Dick Gabriel

I’m always delighted by the light touch and stillness of early programming languages. Not much text; a lot gets done. Old programs read like quiet conversations between a well-spoken research worker and a well- studied mechanical colleague, not as a debate with a compiler. Who’d have guessed sophistication bought such noise?


Shared libraries are not a good thing in general. They add a lot of overhead in this case, but more importantly they also add lots of unnecessary dependencies and complexity, and almost no shared libraries are actually version-safe, so it adds absolutely zero upside.


You can save 2h of reading debugger docs with 12 years of using prints

Jonathan Corbet

The appeal of modern environments is easy enough to understand. A developer working on a function may suddenly discover the need to, say, left-pad a string with blanks. Rather than go though the pain of implementing this challenging functionality, our developer can simply find an appropriate module in the language-specific repository, add it to the project manifest, and use it with no further thought. This allows our developer to take advantage of the work done by others and focus on their core task, which is probably something vital like getting popup windows past ad blockers.


The operation is not to copy but to snarf. It's called snarf because snarf is what it does. There is no design document.

not care about that stuff right now, just want sort and write file mr big brain!

Eskil Steenberg

In the beginning you always want results, in the end all you want is control.


I'm happy if you will make good insane shit with this sample pack


Hardware is becoming faster more slowly than software is becoming slower


Opening my mail over the recycling


Greenspun's Tenth Rule of Programming: any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp."


Godilla99: 0 divided by 0 is pointless. you collard green eating bitch. God motherfucking damn

I leave the geology to the geologists

Simple is not easy and easy is not always simple

You see, we were always busy but seldom productive.

If you've never missed a flight, you're spending too much time in airports

“The thought of light traveling billions of years from distant galaxies only to be washed out in the last billionth of a second by the glow from the nearest strip mall depresses me to no end,”


Things are happening in [location]?

2023 #

Mar 18 - syd streets Darlington

Apr 1 - wildcat zine fair (sydneham)

Apr 1-2: Makers and shakers

May 25-27 - permanent book fair (carriageworks)

May 30-31 - the necks (opera house)


  • tiles/mori
  • floorplan
  • abstract thoughts