about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README20
-rw-r--r--client.c663
-rw-r--r--help.c244
-rw-r--r--index.html4
-rw-r--r--merge.c146
-rw-r--r--meta.c36
-rw-r--r--server.c564
-rw-r--r--sshd_config18
-rw-r--r--torus.h138
10 files changed, 916 insertions, 919 deletions
diff --git a/Makefile b/Makefile
index 6d39351..49377bc 100644
--- a/Makefile
+++ b/Makefile
@@ -45,5 +45,3 @@ tags: *.h *.c
 
 clean:
 	rm -f tags $(BINS) termcap termcap.db chroot.tar
-
-.PHONY: all clean
diff --git a/README b/README
index c4da87e..eda30ad 100644
--- a/README
+++ b/README
@@ -2,14 +2,14 @@ Welcome to ascii.town!
 
 This software targets FreeBSD and Darwin.
 
-    torus.h        Shared structures and message protocol.
-    server.c       Maps torus.dat and listens on torus.sock.
-    client.c       Curses client.
-    help.c         Automated client which redraws a helpful banner.
-    meta.c         Exports metadata from data file to CSV.
-    merge.c        Interactively merges two data files.
-    snapshot.sh    Snapshots data file, appropriate for cron.
+	torus.h        Shared structures and message protocol.
+	server.c       Maps torus.dat and listens on torus.sock.
+	client.c       Curses client.
+	help.c         Automated client which redraws a helpful banner.
+	meta.c         Exports metadata from data file to CSV.
+	merge.c        Interactively merges two data files.
+	snapshot.sh    Snapshots data file, appropriate for cron.
 
-    sshd_config    Anonymous login to chrooted client.
-    termcap.diff   Patch for bright colors in xterm and rxvt.
-    index.html     Friendly directions.
+	sshd_config    Anonymous login to chrooted client.
+	termcap.diff   Patch for bright colors in xterm and rxvt.
+	index.html     Friendly directions.
diff --git a/client.c b/client.c
index 796a81b..a7299ac 100644
--- a/client.c
+++ b/client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, June 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
@@ -30,398 +30,397 @@
 #include "torus.h"
 
 enum {
-    ESC = 0x1B,
-    DEL = 0x7F,
+	ESC = 0x1B,
+	DEL = 0x7F,
 };
 
 static int client;
 
 static void clientMessage(struct ClientMessage msg) {
-    ssize_t size = send(client, &msg, sizeof(msg), 0);
-    if (size < 0) err(EX_IOERR, "send");
+	ssize_t size = send(client, &msg, sizeof(msg), 0);
+	if (size < 0) err(EX_IOERR, "send");
 }
 
 static void clientMove(int8_t dx, int8_t dy) {
-    struct ClientMessage msg = {
-        .type = CLIENT_MOVE,
-        .move = { .dx = dx, .dy = dy },
-    };
-    clientMessage(msg);
+	struct ClientMessage msg = {
+		.type = CLIENT_MOVE,
+		.move = { .dx = dx, .dy = dy },
+	};
+	clientMessage(msg);
 }
 
 static void clientPut(uint8_t color, char cell) {
-    struct ClientMessage msg = {
-        .type = CLIENT_PUT,
-        .put = { .color = color, .cell = cell },
-    };
-    clientMessage(msg);
+	struct ClientMessage msg = {
+		.type = CLIENT_PUT,
+		.put = { .color = color, .cell = cell },
+	};
+	clientMessage(msg);
 }
 
 static void clientSpawn(uint8_t spawn) {
-    struct ClientMessage msg = {
-        .type = CLIENT_SPAWN,
-        .spawn = spawn,
-    };
-    clientMessage(msg);
+	struct ClientMessage msg = {
+		.type = CLIENT_SPAWN,
+		.spawn = spawn,
+	};
+	clientMessage(msg);
 }
 
 static chtype colorAttrs(uint8_t color) {
-    uint8_t bright = color & COLOR_BRIGHT;
-    uint8_t fg = color & 0x07;
-    uint8_t bg = color & 0x70;
-    return COLOR_PAIR(bg >> 1 | fg) | (bright ? A_BOLD : 0);
+	uint8_t bright = color & COLOR_BRIGHT;
+	uint8_t fg = color & 0x07;
+	uint8_t bg = color & 0x70;
+	return COLOR_PAIR(bg >> 1 | fg) | (bright ? A_BOLD : 0);
 }
 
 static uint8_t attrsColor(chtype attrs) {
-    chtype bright = attrs & A_BOLD;
-    short fg = PAIR_NUMBER(attrs) & 007;
-    short bg = PAIR_NUMBER(attrs) & 070;
-    return bg << 1 | fg | (bright ? COLOR_BRIGHT : 0);
+	chtype bright = attrs & A_BOLD;
+	short fg = PAIR_NUMBER(attrs) & 007;
+	short bg = PAIR_NUMBER(attrs) & 070;
+	return bg << 1 | fg | (bright ? COLOR_BRIGHT : 0);
 }
 
 static struct {
-    int8_t speed;
-    uint8_t color;
-    enum {
-        MODE_NORMAL,
-        MODE_INSERT,
-        MODE_REPLACE,
-        MODE_PUT,
-        MODE_DRAW,
-    } mode;
-    int8_t dx;
-    int8_t dy;
-    uint8_t len;
-    char draw;
+	int8_t speed;
+	uint8_t color;
+	enum {
+		MODE_NORMAL,
+		MODE_INSERT,
+		MODE_REPLACE,
+		MODE_PUT,
+		MODE_DRAW,
+	} mode;
+	int8_t dx;
+	int8_t dy;
+	uint8_t len;
+	char draw;
 } input = {
-    .speed = 1,
-    .color = COLOR_WHITE,
-    .dx = 1,
+	.speed = 1,
+	.color = COLOR_WHITE,
+	.dx = 1,
 };
 
 static void colorFg(uint8_t fg) {
-    input.color = (input.color & 0xF8) | fg;
+	input.color = (input.color & 0xF8) | fg;
 }
 
 static void colorBg(uint8_t bg) {
-    input.color = (input.color & 0x0F) | (bg << 4);
+	input.color = (input.color & 0x0F) | (bg << 4);
 }
 
 static void colorInvert(void) {
-    input.color =
-        (input.color & 0x08) |
-        ((input.color & 0x07) << 4) |
-        ((input.color & 0x70) >> 4);
+	input.color =
+		(input.color & 0x08) |
+		((input.color & 0x07) << 4) |
+		((input.color & 0x70) >> 4);
 }
 
 static void insertMode(int8_t dx, int8_t dy) {
-    input.mode = MODE_INSERT;
-    input.dx = dx;
-    input.dy = dy;
-    input.len = 0;
+	input.mode = MODE_INSERT;
+	input.dx = dx;
+	input.dy = dy;
+	input.len = 0;
 }
 
 static void swapCell(int8_t dx, int8_t dy) {
-    uint8_t aColor = attrsColor(inch());
-    char aCell = inch() & A_CHARTEXT;
-
-    int sy, sx;
-    getyx(stdscr, sy, sx);
-    move(sy + dy, sx + dx);
-    uint8_t bColor = attrsColor(inch());
-    char bCell = inch() & A_CHARTEXT;
-    move(sy, sx);
-
-    clientPut(bColor, bCell);
-    clientMove(dx, dy);
-    clientPut(aColor, aCell);
+	uint8_t aColor = attrsColor(inch());
+	char aCell = inch() & A_CHARTEXT;
+
+	int sy, sx;
+	getyx(stdscr, sy, sx);
+	move(sy + dy, sx + dx);
+	uint8_t bColor = attrsColor(inch());
+	char bCell = inch() & A_CHARTEXT;
+	move(sy, sx);
+
+	clientPut(bColor, bCell);
+	clientMove(dx, dy);
+	clientPut(aColor, aCell);
 }
 
 static void readInput(void) {
-    int c = getch();
-
-    if (input.mode == MODE_INSERT) {
-        if (c == ESC) {
-            input.mode = MODE_NORMAL;
-            clientMove(-input.dx, -input.dy);
-        } else if (!input.dx && !input.dy) {
-            switch (c) {
-                case 'h': insertMode(-1,  0); break;
-                case 'j': insertMode( 0,  1); break;
-                case 'k': insertMode( 0, -1); break;
-                case 'l': insertMode( 1,  0); break;
-                case 'y': insertMode(-1, -1); break;
-                case 'u': insertMode( 1, -1); break;
-                case 'b': insertMode(-1,  1); break;
-                case 'n': insertMode( 1,  1); break;
-            }
-        } else if (c == '\b' || c == DEL) {
-            clientMove(-input.dx, -input.dy);
-            clientPut(input.color, ' ');
-            input.len--;
-        } else if (c == '\n') {
-            clientMove(input.dy, input.dx);
-            clientMove(-input.dx * input.len, -input.dy * input.len);
-            input.len = 0;
-        } else if (isprint(c)) {
-            clientPut(input.color, c);
-            clientMove(input.dx, input.dy);
-            input.len++;
-        }
-        return;
-    }
-
-    if (input.mode == MODE_REPLACE) {
-        if (isprint(c)) clientPut(attrsColor(inch()), c);
-        input.mode = MODE_NORMAL;
-        return;
-    }
-
-    if (input.mode == MODE_PUT) {
-        if (isprint(c)) clientPut(input.color, c);
-        input.mode = MODE_NORMAL;
-        return;
-    }
-
-    if (input.mode == MODE_DRAW && !input.draw) {
-        if (c == ESC) input.mode = MODE_NORMAL;
-        if (isprint(c)) {
-            input.draw = c;
-            clientPut(input.color, c);
-        }
-        return;
-    }
-
-    switch (c) {
-        case ESC: input.mode = MODE_NORMAL; break;
-
-        case 'q': endwin(); exit(EX_OK);
-        case 'Q': {
-            if ((input.color & 0x07) < SPAWNS_LEN) {
-                clientSpawn(input.color & 0x07);
-            } else {
-                clientSpawn(0);
-            }
-        } break;
-
-        case 'a': clientMove(1, 0); // fallthrough
-        case 'i': insertMode(1, 0); break;
-        case 'I': insertMode(0, 0); break;
-        case 'r': input.mode = MODE_REPLACE; break;
-        case 'p': input.mode = MODE_PUT; break;
-        case 'R': input.mode = MODE_DRAW; input.draw = 0; break;
-        case 'x': clientPut(attrsColor(inch()), ' '); break;
-
-        case '~': {
-            clientPut(input.color, inch() & A_CHARTEXT);
-            clientMove(input.dx, input.dy);
-        } break;
-
-        case '[': if (input.speed > 1) input.speed--; break;
-        case ']': if (input.speed < 4) input.speed++; break;
-
-        case 'h': clientMove(-input.speed,            0); break;
-        case 'j': clientMove(           0,  input.speed); break;
-        case 'k': clientMove(           0, -input.speed); break;
-        case 'l': clientMove( input.speed,            0); break;
-        case 'y': clientMove(-input.speed, -input.speed); break;
-        case 'u': clientMove( input.speed, -input.speed); break;
-        case 'b': clientMove(-input.speed,  input.speed); break;
-        case 'n': clientMove( input.speed,  input.speed); break;
-
-        case 'H': swapCell(-1,  0); break;
-        case 'J': swapCell( 0,  1); break;
-        case 'K': swapCell( 0, -1); break;
-        case 'L': swapCell( 1,  0); break;
-        case 'Y': swapCell(-1, -1); break;
-        case 'U': swapCell( 1, -1); break;
-        case 'B': swapCell(-1,  1); break;
-        case 'N': swapCell( 1,  1); break;
-
-        case '`': input.color = attrsColor(inch()); break;
-
-        case '0': colorFg(COLOR_BLACK);   break;
-        case '1': colorFg(COLOR_RED);     break;
-        case '2': colorFg(COLOR_GREEN);   break;
-        case '3': colorFg(COLOR_YELLOW);  break;
-        case '4': colorFg(COLOR_BLUE);    break;
-        case '5': colorFg(COLOR_MAGENTA); break;
-        case '6': colorFg(COLOR_CYAN);    break;
-        case '7': colorFg(COLOR_WHITE);   break;
-
-        case ')': colorBg(COLOR_BLACK);   break;
-        case '!': colorBg(COLOR_RED);     break;
-        case '@': colorBg(COLOR_GREEN);   break;
-        case '#': colorBg(COLOR_YELLOW);  break;
-        case '$': colorBg(COLOR_BLUE);    break;
-        case '%': colorBg(COLOR_MAGENTA); break;
-        case '^': colorBg(COLOR_CYAN);    break;
-        case '&': colorBg(COLOR_WHITE);   break;
-
-        case '*':
-        case '8': input.color ^= COLOR_BRIGHT; break;
-
-        case '(':
-        case '9': colorInvert(); break;
-
-        case KEY_LEFT:  clientMove(-1,  0); break;
-        case KEY_DOWN:  clientMove( 0,  1); break;
-        case KEY_UP:    clientMove( 0, -1); break;
-        case KEY_RIGHT: clientMove( 1,  0); break;
-    }
-
-    if (input.mode == MODE_DRAW && input.draw) clientPut(input.color, input.draw);
+	int c = getch();
+
+	if (input.mode == MODE_INSERT) {
+		if (c == ESC) {
+			input.mode = MODE_NORMAL;
+			clientMove(-input.dx, -input.dy);
+		} else if (!input.dx && !input.dy) {
+			switch (c) {
+				break; case 'h': insertMode(-1,  0);
+				break; case 'j': insertMode( 0,  1);
+				break; case 'k': insertMode( 0, -1);
+				break; case 'l': insertMode( 1,  0);
+				break; case 'y': insertMode(-1, -1);
+				break; case 'u': insertMode( 1, -1);
+				break; case 'b': insertMode(-1,  1);
+				break; case 'n': insertMode( 1,  1);
+			}
+		} else if (c == '\b' || c == DEL) {
+			clientMove(-input.dx, -input.dy);
+			clientPut(input.color, ' ');
+			input.len--;
+		} else if (c == '\n') {
+			clientMove(input.dy, input.dx);
+			clientMove(-input.dx * input.len, -input.dy * input.len);
+			input.len = 0;
+		} else if (isprint(c)) {
+			clientPut(input.color, c);
+			clientMove(input.dx, input.dy);
+			input.len++;
+		}
+		return;
+	}
+
+	if (input.mode == MODE_REPLACE) {
+		if (isprint(c)) clientPut(attrsColor(inch()), c);
+		input.mode = MODE_NORMAL;
+		return;
+	}
+
+	if (input.mode == MODE_PUT) {
+		if (isprint(c)) clientPut(input.color, c);
+		input.mode = MODE_NORMAL;
+		return;
+	}
+
+	if (input.mode == MODE_DRAW && !input.draw) {
+		if (c == ESC) input.mode = MODE_NORMAL;
+		if (isprint(c)) {
+			input.draw = c;
+			clientPut(input.color, c);
+		}
+		return;
+	}
+
+	switch (c) {
+		break; case ESC: input.mode = MODE_NORMAL;
+
+		break; case 'q': endwin(); exit(EX_OK);
+		break; case 'Q': {
+			if ((input.color & 0x07) < SPAWNS_LEN) {
+				clientSpawn(input.color & 0x07);
+			} else {
+				clientSpawn(0);
+			}
+		}
+
+		break; case 'i': insertMode(1, 0);
+		break; case 'a': clientMove(1, 0); insertMode(1, 0);
+		break; case 'I': insertMode(0, 0);
+		break; case 'r': input.mode = MODE_REPLACE;
+		break; case 'p': input.mode = MODE_PUT;
+		break; case 'R': input.mode = MODE_DRAW; input.draw = 0;
+		break; case 'x': clientPut(attrsColor(inch()), ' ');
+
+		break; case '~': {
+			clientPut(input.color, inch() & A_CHARTEXT);
+			clientMove(input.dx, input.dy);
+		}
+
+		break; case '[': if (input.speed > 1) input.speed--;
+		break; case ']': if (input.speed < 4) input.speed++;
+
+		break; case 'h': clientMove(-input.speed,            0);
+		break; case 'j': clientMove(           0,  input.speed);
+		break; case 'k': clientMove(           0, -input.speed);
+		break; case 'l': clientMove( input.speed,            0);
+		break; case 'y': clientMove(-input.speed, -input.speed);
+		break; case 'u': clientMove( input.speed, -input.speed);
+		break; case 'b': clientMove(-input.speed,  input.speed);
+		break; case 'n': clientMove( input.speed,  input.speed);
+
+		break; case 'H': swapCell(-1,  0);
+		break; case 'J': swapCell( 0,  1);
+		break; case 'K': swapCell( 0, -1);
+		break; case 'L': swapCell( 1,  0);
+		break; case 'Y': swapCell(-1, -1);
+		break; case 'U': swapCell( 1, -1);
+		break; case 'B': swapCell(-1,  1);
+		break; case 'N': swapCell( 1,  1);
+
+		break; case '`': input.color = attrsColor(inch());
+
+		break; case '0': colorFg(COLOR_BLACK);
+		break; case '1': colorFg(COLOR_RED);
+		break; case '2': colorFg(COLOR_GREEN);
+		break; case '3': colorFg(COLOR_YELLOW);
+		break; case '4': colorFg(COLOR_BLUE);
+		break; case '5': colorFg(COLOR_MAGENTA);
+		break; case '6': colorFg(COLOR_CYAN);
+		break; case '7': colorFg(COLOR_WHITE);
+
+		break; case ')': colorBg(COLOR_BLACK);
+		break; case '!': colorBg(COLOR_RED);
+		break; case '@': colorBg(COLOR_GREEN);
+		break; case '#': colorBg(COLOR_YELLOW);
+		break; case '$': colorBg(COLOR_BLUE);
+		break; case '%': colorBg(COLOR_MAGENTA);
+		break; case '^': colorBg(COLOR_CYAN);
+		break; case '&': colorBg(COLOR_WHITE);
+
+		break; case '*': case '8': input.color ^= COLOR_BRIGHT;
+
+		break; case '(': case '9': colorInvert();
+
+		break; case KEY_LEFT:  clientMove(-1,  0);
+		break; case KEY_DOWN:  clientMove( 0,  1);
+		break; case KEY_UP:    clientMove( 0, -1);
+		break; case KEY_RIGHT: clientMove( 1,  0);
+	}
+
+	if (input.mode == MODE_DRAW && input.draw) clientPut(input.color, input.draw);
 }
 
 static void serverPut(uint8_t x, uint8_t y, uint8_t color, char cell) {
-    mvaddch(y, x, colorAttrs(color) | cell);
+	mvaddch(y, x, colorAttrs(color) | cell);
 }
 
 static void serverTile(void) {
-    struct Tile tile;
-    ssize_t size = recv(client, &tile, sizeof(tile), 0);
-    if (size < 0) err(EX_IOERR, "recv");
-    if ((size_t)size < sizeof(tile)) {
-        errx(EX_PROTOCOL, "This tile isn't big enough...");
-    }
-
-    for (int y = 0; y < CELL_ROWS; ++y) {
-        for (int x = 0; x < CELL_COLS; ++x) {
-            serverPut(x, y, tile.colors[y][x], tile.cells[y][x]);
-        }
-    }
+	struct Tile tile;
+	ssize_t size = recv(client, &tile, sizeof(tile), 0);
+	if (size < 0) err(EX_IOERR, "recv");
+	if ((size_t)size < sizeof(tile)) {
+		errx(EX_PROTOCOL, "This tile isn't big enough...");
+	}
+
+	for (int y = 0; y < CELL_ROWS; ++y) {
+		for (int x = 0; x < CELL_COLS; ++x) {
+			serverPut(x, y, tile.colors[y][x], tile.cells[y][x]);
+		}
+	}
 }
 
 static void serverCursor(uint8_t oldX, uint8_t oldY, uint8_t newX, uint8_t newY) {
-    if (oldX != CURSOR_NONE) {
-        move(oldY, oldX);
-        addch(inch() & ~A_REVERSE);
-    }
-    if (newX != CURSOR_NONE) {
-        move(newY, newX);
-        addch(inch() | A_REVERSE);
-    }
+	if (oldX != CURSOR_NONE) {
+		move(oldY, oldX);
+		addch(inch() & ~A_REVERSE);
+	}
+	if (newX != CURSOR_NONE) {
+		move(newY, newX);
+		addch(inch() | A_REVERSE);
+	}
 }
 
 static void readMessage(void) {
-    struct ServerMessage msg;
-    ssize_t size = recv(client, &msg, sizeof(msg), 0);
-    if (size < 0) err(EX_IOERR, "recv");
-    if ((size_t)size < sizeof(msg)) errx(EX_PROTOCOL, "A message was cut short.");
-
-    int sy, sx;
-    getyx(stdscr, sy, sx);
-
-    switch (msg.type) {
-        case SERVER_TILE: {
-            serverTile();
-        } break;
-
-        case SERVER_MOVE: {
-            move(msg.move.cellY, msg.move.cellX);
-            refresh();
-        } return;
-
-        case SERVER_PUT: {
-            serverPut(
-                msg.put.cellX,
-                msg.put.cellY,
-                msg.put.color,
-                msg.put.cell
-            );
-        } break;
-
-        case SERVER_CURSOR: {
-            serverCursor(
-                msg.cursor.oldCellX,
-                msg.cursor.oldCellY,
-                msg.cursor.newCellX,
-                msg.cursor.newCellY
-            );
-        } break;
-
-        default: errx(EX_PROTOCOL, "I don't know what %d means!", msg.type);
-    }
-
-    move(sy, sx);
-    refresh();
+	struct ServerMessage msg;
+	ssize_t size = recv(client, &msg, sizeof(msg), 0);
+	if (size < 0) err(EX_IOERR, "recv");
+	if ((size_t)size < sizeof(msg)) errx(EX_PROTOCOL, "A message was cut short.");
+
+	int sy, sx;
+	getyx(stdscr, sy, sx);
+
+	switch (msg.type) {
+		break; case SERVER_TILE: {
+			serverTile();
+		}
+
+		break; case SERVER_MOVE: {
+			move(msg.move.cellY, msg.move.cellX);
+			refresh();
+			return;
+		}
+
+		break; case SERVER_PUT: {
+			serverPut(
+				msg.put.cellX,
+				msg.put.cellY,
+				msg.put.color,
+				msg.put.cell
+			);
+		}
+
+		break; case SERVER_CURSOR: {
+			serverCursor(
+				msg.cursor.oldCellX,
+				msg.cursor.oldCellY,
+				msg.cursor.newCellX,
+				msg.cursor.newCellY
+			);
+		}
+
+		break; default: errx(EX_PROTOCOL, "I don't know what %d means!", msg.type);
+	}
+
+	move(sy, sx);
+	refresh();
 }
 
 static void drawBorder(void) {
-    if (LINES < CELL_ROWS || COLS < CELL_COLS) {
-        endwin();
-        fprintf(stderr, "Sorry, your terminal is too small!\n");
-        fprintf(stderr, "It needs to be at least 80x25 characters.\n");
-        exit(EX_CONFIG);
-    }
-    if (LINES > CELL_ROWS) {
-        mvhline(CELL_ROWS, 0, 0, CELL_COLS);
-    }
-    if (COLS > CELL_COLS) {
-        mvvline(0, CELL_COLS, 0, CELL_ROWS);
-    }
-    if (LINES > CELL_ROWS && COLS > CELL_COLS) {
-        mvaddch(CELL_ROWS, CELL_COLS, ACS_LRCORNER);
-    }
+	if (LINES < CELL_ROWS || COLS < CELL_COLS) {
+		endwin();
+		fprintf(stderr, "Sorry, your terminal is too small!\n");
+		fprintf(stderr, "It needs to be at least 80x25 characters.\n");
+		exit(EX_CONFIG);
+	}
+	if (LINES > CELL_ROWS) {
+		mvhline(CELL_ROWS, 0, 0, CELL_COLS);
+	}
+	if (COLS > CELL_COLS) {
+		mvvline(0, CELL_COLS, 0, CELL_ROWS);
+	}
+	if (LINES > CELL_ROWS && COLS > CELL_COLS) {
+		mvaddch(CELL_ROWS, CELL_COLS, ACS_LRCORNER);
+	}
 }
 
 static void initColors(void) {
-    if (!has_colors()) {
-        endwin();
-        fprintf(
-            stderr,
-            "Sorry, your terminal doesn't support colors!\n"
-            "If you think it does, check TERM.\n"
-        );
-        exit(EX_CONFIG);
-    }
-    start_color();
-    if (COLOR_PAIRS < 64) {
-        endwin();
-        fprintf(
-            stderr,
-            "Sorry, your terminal doesn't support enough color pairs!\n"
-            "If you think it does, check TERM.\n"
-        );
-        exit(EX_CONFIG);
-    }
-    for (int bg = COLOR_BLACK; bg < COLOR_BRIGHT; ++bg) {
-        for (int fg = COLOR_BLACK; fg < COLOR_BRIGHT; ++fg) {
-            init_pair(PAIR_NUMBER(colorAttrs(bg << 4 | fg)), fg, bg);
-        }
-    }
+	if (!has_colors()) {
+		endwin();
+		fprintf(
+			stderr,
+			"Sorry, your terminal doesn't support colors!\n"
+			"If you think it does, check TERM.\n"
+		);
+		exit(EX_CONFIG);
+	}
+	start_color();
+	if (COLOR_PAIRS < 64) {
+		endwin();
+		fprintf(
+			stderr,
+			"Sorry, your terminal doesn't support enough color pairs!\n"
+			"If you think it does, check TERM.\n"
+		);
+		exit(EX_CONFIG);
+	}
+	for (int bg = COLOR_BLACK; bg < COLOR_BRIGHT; ++bg) {
+		for (int fg = COLOR_BLACK; fg < COLOR_BRIGHT; ++fg) {
+			init_pair(PAIR_NUMBER(colorAttrs(bg << 4 | fg)), fg, bg);
+		}
+	}
 }
 
 int main() {
-    client = socket(PF_LOCAL, SOCK_STREAM, 0);
-    if (client < 0) err(EX_OSERR, "socket");
-
-    struct sockaddr_un addr = {
-        .sun_family = AF_LOCAL,
-        .sun_path = "torus.sock",
-    };
-    int error = connect(client, (struct sockaddr *)&addr, sizeof(addr));
-    if (error) err(EX_NOINPUT, "torus.sock");
-
-    initscr();
-    cbreak();
-    noecho();
-    keypad(stdscr, true);
-    set_escdelay(100);
-
-    initColors();
-    drawBorder();
-
-    struct pollfd fds[2] = {
-        { .fd = STDIN_FILENO, .events = POLLIN },
-        { .fd = client, .events = POLLIN },
-    };
-    for (;;) {
-        int nfds = poll(fds, 2, -1);
-        if (nfds < 0 && errno == EINTR) continue;
-        if (nfds < 0) err(EX_IOERR, "poll");
-
-        if (fds[0].revents) readInput();
-        if (fds[1].revents) readMessage();
-    }
+	client = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (client < 0) err(EX_OSERR, "socket");
+
+	struct sockaddr_un addr = {
+		.sun_family = AF_LOCAL,
+		.sun_path = "torus.sock",
+	};
+	int error = connect(client, (struct sockaddr *)&addr, sizeof(addr));
+	if (error) err(EX_NOINPUT, "torus.sock");
+
+	initscr();
+	cbreak();
+	noecho();
+	keypad(stdscr, true);
+	set_escdelay(100);
+
+	initColors();
+	drawBorder();
+
+	struct pollfd fds[2] = {
+		{ .fd = STDIN_FILENO, .events = POLLIN },
+		{ .fd = client, .events = POLLIN },
+	};
+	for (;;) {
+		int nfds = poll(fds, 2, -1);
+		if (nfds < 0 && errno == EINTR) continue;
+		if (nfds < 0) err(EX_IOERR, "poll");
+
+		if (fds[0].revents) readInput();
+		if (fds[1].revents) readMessage();
+	}
 }
diff --git a/help.c b/help.c
index 8d45c83..f000638 100644
--- a/help.c
+++ b/help.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, June 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
@@ -26,37 +26,37 @@
 static int client;
 
 static void clientMessage(struct ClientMessage msg) {
-    ssize_t size = send(client, &msg, sizeof(msg), 0);
-    if (size < 0) err(EX_IOERR, "send");
+	ssize_t size = send(client, &msg, sizeof(msg), 0);
+	if (size < 0) err(EX_IOERR, "send");
 }
 
 static void clientMove(int8_t dx, int8_t dy) {
-    struct ClientMessage msg = {
-        .type = CLIENT_MOVE,
-        .move = { .dx = dx, .dy = dy },
-    };
-    clientMessage(msg);
+	struct ClientMessage msg = {
+		.type = CLIENT_MOVE,
+		.move = { .dx = dx, .dy = dy },
+	};
+	clientMessage(msg);
 }
 
 static void clientPut(uint8_t color, char cell) {
-    struct ClientMessage msg = {
-        .type = CLIENT_PUT,
-        .put = { .color = color, .cell = cell },
-    };
-    clientMessage(msg);
+	struct ClientMessage msg = {
+		.type = CLIENT_PUT,
+		.put = { .color = color, .cell = cell },
+	};
+	clientMessage(msg);
 }
 
 static const useconds_t DELAY = 50000;
 
 enum {
-    R = COLOR_RED,
-    G = COLOR_GREEN,
-    Y = COLOR_YELLOW,
-    B = COLOR_BLUE,
-    M = COLOR_MAGENTA,
-    C = COLOR_CYAN,
-    W = COLOR_WHITE,
-    I = COLOR_BRIGHT | COLOR_WHITE,
+	R = COLOR_RED,
+	G = COLOR_GREEN,
+	Y = COLOR_YELLOW,
+	B = COLOR_BLUE,
+	M = COLOR_MAGENTA,
+	C = COLOR_CYAN,
+	W = COLOR_WHITE,
+	I = COLOR_BRIGHT | COLOR_WHITE,
 };
 
 static void h(void) { clientMove(-1,  0); usleep(DELAY); }
@@ -69,116 +69,116 @@ static void b(void) { clientMove(-1,  1); usleep(DELAY); }
 static void n(void) { clientMove( 1,  1); usleep(DELAY); }
 
 static void p(uint8_t color, char cell) {
-    clientPut(color, cell);
-    usleep(DELAY);
+	clientPut(color, cell);
+	usleep(DELAY);
 }
 
 static uint8_t len;
 
 static void s(uint8_t color, const char *str) {
-    for (; *str; ++len, ++str) {
-        clientPut(color, *str);
-        clientMove(1, 0);
-        usleep(DELAY);
-    }
+	for (; *str; ++len, ++str) {
+		clientPut(color, *str);
+		clientMove(1, 0);
+		usleep(DELAY);
+	}
 }
 
 static void r(void) {
-    clientMove(-len, 1);
-    usleep(DELAY);
-    len = 0;
+	clientMove(-len, 1);
+	usleep(DELAY);
+	len = 0;
 }
 
 int main() {
-    client = socket(PF_LOCAL, SOCK_STREAM, 0);
-    if (client < 0) err(EX_OSERR, "socket");
-
-    struct sockaddr_un addr = {
-        .sun_family = AF_LOCAL,
-        .sun_path = "torus.sock",
-    };
-    int error = connect(client, (struct sockaddr *)&addr, sizeof(addr));
-    if (error) err(EX_NOINPUT, "torus.sock");
-
-    pid_t pid = fork();
-    if (pid < 0) err(EX_OSERR, "fork");
-
-    if (!pid) {
-        for (;;) {
-            char buf[4096];
-            ssize_t size = recv(client, buf, sizeof(buf), 0);
-            if (size < 0) err(EX_IOERR, "recv");
-            if (!size) return EX_OK;
-        }
-    }
-
-    clientMove(-CELL_INIT_X, -CELL_INIT_Y);
-    clientMove(28, 0);
-
-    for (;;) {
-        for (int i = 0; i < 10; ++i) {
-            clientMove(0, 1);
-            usleep(DELAY / 5);
-        }
-        for (int i = 0; i < 11; ++i) {
-            for (int j = 0; j < 28; ++j) {
-                clientPut(W, ' ');
-                if (i % 2) clientMove(1, 0);
-                else clientMove(-1, 0);
-                usleep(DELAY / 5);
-            }
-            clientPut(W, ' ');
-            if (i != 10) clientMove(0, -1);
-            usleep(DELAY / 5);
-        }
-
-        j(); l(); l();
-        s(W, "Welcome to "); s(I, "ascii.town"); s(W, "!"); r();
-        r(); r();
-
-        n(); n(); s(W, "o-"); s(I, "l");
-        h(); b(); p(W, '\\'); n(); p(I, 'n');
-        y(); h(); p(W, '|'); j(); p(I, 'j');
-        y(); p(W, '/'); b(); p(I, 'b');
-        k(); u(); p(W, '-'); h(); p(I, 'h');
-        u(); p(W, '\\'); y(); p(I, 'y');
-        n(); l(); p(W, '|'); k(); p(I, 'k');
-        n(); p(W, '/');  u(); p(I, 'u');
-
-        u(); s(W, "    "); len = 0;
-
-        s(I, "q "); s(W, "quit");    r();
-        s(I, "i "); s(W, "insert");  r();
-        s(I, "r "); s(W, "replace"); r();
-        s(I, "R "); s(W, "draw");    r();
-        s(I, "~ "); s(W, "color");   r();
-        s(I, "` "); s(W, "pipette"); r();
-        s(I, "* "); s(W, "bright");
-
-        s(W, "     "); len = 0;
-
-        clientPut(W, '7'); k();
-        clientPut(C, '6'); k();
-        clientPut(M, '5'); k();
-        clientPut(B, '4'); k();
-        clientPut(Y, '3'); k();
-        clientPut(G, '2'); k();
-        clientPut(R, '1'); k();
-
-        l(); n();
-
-        clientPut(R << 4, '!'); j();
-        clientPut(G << 4, '@'); j();
-        clientPut(Y << 4, '#'); j();
-        clientPut(B << 4, '$'); j();
-        clientPut(M << 4, '%'); j();
-        clientPut(C << 4, '^'); j();
-        clientPut(W << 4, '&'); j();
-
-        h(); k(); k(); k(); k(); k(); k(); k(); k(); k(); h();
-
-        sleep(30);
-
-        u(); l(); l(); l();
-    }
+	client = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (client < 0) err(EX_OSERR, "socket");
+
+	struct sockaddr_un addr = {
+		.sun_family = AF_LOCAL,
+		.sun_path = "torus.sock",
+	};
+	int error = connect(client, (struct sockaddr *)&addr, sizeof(addr));
+	if (error) err(EX_NOINPUT, "torus.sock");
+
+	pid_t pid = fork();
+	if (pid < 0) err(EX_OSERR, "fork");
+
+	if (!pid) {
+		for (;;) {
+			char buf[4096];
+			ssize_t size = recv(client, buf, sizeof(buf), 0);
+			if (size < 0) err(EX_IOERR, "recv");
+			if (!size) return EX_OK;
+		}
+	}
+
+	clientMove(-CELL_INIT_X, -CELL_INIT_Y);
+	clientMove(28, 0);
+
+	for (;;) {
+		for (int i = 0; i < 10; ++i) {
+			clientMove(0, 1);
+			usleep(DELAY / 5);
+		}
+		for (int i = 0; i < 11; ++i) {
+			for (int j = 0; j < 28; ++j) {
+				clientPut(W, ' ');
+				if (i % 2) clientMove(1, 0);
+				else clientMove(-1, 0);
+				usleep(DELAY / 5);
+			}
+			clientPut(W, ' ');
+			if (i != 10) clientMove(0, -1);
+			usleep(DELAY / 5);
+		}
+
+		j(); l(); l();
+		s(W, "Welcome to "); s(I, "ascii.town"); s(W, "!"); r();
+		r(); r();
+
+		n(); n(); s(W, "o-"); s(I, "l");
+		h(); b(); p(W, '\\'); n(); p(I, 'n');
+		y(); h(); p(W, '|'); j(); p(I, 'j');
+		y(); p(W, '/'); b(); p(I, 'b');
+		k(); u(); p(W, '-'); h(); p(I, 'h');
+		u(); p(W, '\\'); y(); p(I, 'y');
+		n(); l(); p(W, '|'); k(); p(I, 'k');
+		n(); p(W, '/');  u(); p(I, 'u');
+
+		u(); s(W, "    "); len = 0;
+
+		s(I, "q "); s(W, "quit");    r();
+		s(I, "i "); s(W, "insert");  r();
+		s(I, "r "); s(W, "replace"); r();
+		s(I, "R "); s(W, "draw");    r();
+		s(I, "~ "); s(W, "color");   r();
+		s(I, "` "); s(W, "pipette"); r();
+		s(I, "* "); s(W, "bright");
+
+		s(W, "     "); len = 0;
+
+		clientPut(W, '7'); k();
+		clientPut(C, '6'); k();
+		clientPut(M, '5'); k();
+		clientPut(B, '4'); k();
+		clientPut(Y, '3'); k();
+		clientPut(G, '2'); k();
+		clientPut(R, '1'); k();
+
+		l(); n();
+
+		clientPut(R << 4, '!'); j();
+		clientPut(G << 4, '@'); j();
+		clientPut(Y << 4, '#'); j();
+		clientPut(B << 4, '$'); j();
+		clientPut(M << 4, '%'); j();
+		clientPut(C << 4, '^'); j();
+		clientPut(W << 4, '&'); j();
+
+		h(); k(); k(); k(); k(); k(); k(); k(); k(); k(); h();
+
+		sleep(30);
+
+		u(); l(); l(); l();
+	}
 }
diff --git a/index.html b/index.html
index ad0c46a..3874b1a 100644
--- a/index.html
+++ b/index.html
@@ -4,11 +4,11 @@
 Hey there, friend. This should get you there.
 <p>
 <code>
-    ssh torus@ascii.town
+	ssh torus@ascii.town
 </code>
 <p>
 You can also take a detour and play NetHack.
 <p>
 <code>
-    ssh nethack@ascii.town
+	ssh nethack@ascii.town
 </code>
diff --git a/merge.c b/merge.c
index aec875a..7ae7cac 100644
--- a/merge.c
+++ b/merge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, June 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
@@ -23,79 +23,79 @@
 #include "torus.h"
 
 static void drawTile(int offsetY, const struct Tile *tile) {
-    for (uint8_t y = 0; y < CELL_ROWS; ++y) {
-        for (uint8_t x = 0; x < CELL_COLS; ++x) {
-            uint8_t color = tile->colors[y][x];
-            char cell = tile->cells[y][x];
-
-            int attrs = COLOR_PAIR(color & ~COLOR_BRIGHT);
-            if (color & COLOR_BRIGHT) attrs |= A_BOLD;
-            mvaddch(offsetY + y, x, attrs | cell);
-        }
-    }
+	for (uint8_t y = 0; y < CELL_ROWS; ++y) {
+		for (uint8_t x = 0; x < CELL_COLS; ++x) {
+			uint8_t color = tile->colors[y][x];
+			char cell = tile->cells[y][x];
+
+			int attrs = COLOR_PAIR(color & ~COLOR_BRIGHT);
+			if (color & COLOR_BRIGHT) attrs |= A_BOLD;
+			mvaddch(offsetY + y, x, attrs | cell);
+		}
+	}
 }
 
 int main(int argc, char *argv[]) {
-    if (argc != 4) return EX_USAGE;
-
-    FILE *fileA = fopen(argv[1], "r");
-    if (!fileA) err(EX_NOINPUT, "%s", argv[1]);
-
-    FILE *fileB = fopen(argv[2], "r");
-    if (!fileB) err(EX_NOINPUT, "%s", argv[2]);
-
-    FILE *fileC = fopen(argv[3], "w");
-    if (!fileC) err(EX_CANTCREAT, "%s", argv[3]);
-
-    initscr();
-    cbreak();
-    noecho();
-    keypad(stdscr, true);
-    set_escdelay(100);
-
-    start_color();
-    for (int bg = COLOR_BLACK; bg < COLOR_BRIGHT; ++bg) {
-        for (int fg = COLOR_BLACK; fg < COLOR_BRIGHT; ++fg) {
-            init_pair(bg << 4 | fg, fg, bg);
-        }
-    }
-
-    mvhline(CELL_ROWS, 0, 0, CELL_COLS);
-    mvhline(CELL_ROWS * 2 + 1, 0, 0, CELL_COLS);
-    mvvline(0, CELL_COLS, 0, CELL_ROWS * 2 + 1);
-    mvaddch(CELL_ROWS, CELL_COLS, ACS_RTEE);
-    mvaddch(CELL_ROWS * 2 + 1, CELL_COLS, ACS_LRCORNER);
-
-    struct Tile tileA, tileB;
-    for (;;) {
-        size_t countA = fread(&tileA, sizeof(tileA), 1, fileA);
-        if (ferror(fileA)) err(EX_IOERR, "%s", argv[1]);
-
-        size_t countB = fread(&tileB, sizeof(tileB), 1, fileB);
-        if (ferror(fileB)) err(EX_IOERR, "%s", argv[2]);
-
-        if (!countA && !countB) break;
-        if (!countA || !countB) errx(EX_DATAERR, "different size inputs");
-
-        const struct Tile *tileC = (tileA.accessTime > tileB.accessTime)
-            ? &tileA
-            : &tileB;
-
-        if (tileA.modifyTime != tileB.modifyTime) {
-            drawTile(0, &tileA);
-            drawTile(CELL_ROWS + 1, &tileB);
-            move(CELL_ROWS * 2 + 2, 0);
-            refresh();
-
-            int c;
-            do { c = getch(); } while (c != 'a' && c != 'b');
-            tileC = (c == 'a') ? &tileA : &tileB;
-        }
-
-        fwrite(tileC, sizeof(*tileC), 1, fileC);
-        if (ferror(fileC)) err(EX_IOERR, "%s", argv[3]);
-    }
-
-    endwin();
-    return EX_OK;
+	if (argc != 4) return EX_USAGE;
+
+	FILE *fileA = fopen(argv[1], "r");
+	if (!fileA) err(EX_NOINPUT, "%s", argv[1]);
+
+	FILE *fileB = fopen(argv[2], "r");
+	if (!fileB) err(EX_NOINPUT, "%s", argv[2]);
+
+	FILE *fileC = fopen(argv[3], "w");
+	if (!fileC) err(EX_CANTCREAT, "%s", argv[3]);
+
+	initscr();
+	cbreak();
+	noecho();
+	keypad(stdscr, true);
+	set_escdelay(100);
+
+	start_color();
+	for (int bg = COLOR_BLACK; bg < COLOR_BRIGHT; ++bg) {
+		for (int fg = COLOR_BLACK; fg < COLOR_BRIGHT; ++fg) {
+			init_pair(bg << 4 | fg, fg, bg);
+		}
+	}
+
+	mvhline(CELL_ROWS, 0, 0, CELL_COLS);
+	mvhline(CELL_ROWS * 2 + 1, 0, 0, CELL_COLS);
+	mvvline(0, CELL_COLS, 0, CELL_ROWS * 2 + 1);
+	mvaddch(CELL_ROWS, CELL_COLS, ACS_RTEE);
+	mvaddch(CELL_ROWS * 2 + 1, CELL_COLS, ACS_LRCORNER);
+
+	struct Tile tileA, tileB;
+	for (;;) {
+		size_t countA = fread(&tileA, sizeof(tileA), 1, fileA);
+		if (ferror(fileA)) err(EX_IOERR, "%s", argv[1]);
+
+		size_t countB = fread(&tileB, sizeof(tileB), 1, fileB);
+		if (ferror(fileB)) err(EX_IOERR, "%s", argv[2]);
+
+		if (!countA && !countB) break;
+		if (!countA || !countB) errx(EX_DATAERR, "different size inputs");
+
+		const struct Tile *tileC = (tileA.accessTime > tileB.accessTime)
+			? &tileA
+			: &tileB;
+
+		if (tileA.modifyTime != tileB.modifyTime) {
+			drawTile(0, &tileA);
+			drawTile(CELL_ROWS + 1, &tileB);
+			move(CELL_ROWS * 2 + 2, 0);
+			refresh();
+
+			int c;
+			do { c = getch(); } while (c != 'a' && c != 'b');
+			tileC = (c == 'a') ? &tileA : &tileB;
+		}
+
+		fwrite(tileC, sizeof(*tileC), 1, fileC);
+		if (ferror(fileC)) err(EX_IOERR, "%s", argv[3]);
+	}
+
+	endwin();
+	return EX_OK;
 }
diff --git a/meta.c b/meta.c
index ede1041..2ab906f 100644
--- a/meta.c
+++ b/meta.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, June 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
@@ -21,22 +21,22 @@
 #include "torus.h"
 
 int main() {
-    printf("tileX,tileY,createTime,modifyCount,modifyTime,accessCount,accessTime\n");
-    for (int i = 0;; ++i) {
-        struct Tile tile;
-        size_t count = fread(&tile, sizeof(tile), 1, stdin);
-        if (ferror(stdin)) err(EX_IOERR, "(stdin)");
-        if (!count) return EX_OK;
+	printf("tileX,tileY,createTime,modifyCount,modifyTime,accessCount,accessTime\n");
+	for (int i = 0;; ++i) {
+		struct Tile tile;
+		size_t count = fread(&tile, sizeof(tile), 1, stdin);
+		if (ferror(stdin)) err(EX_IOERR, "(stdin)");
+		if (!count) return EX_OK;
 
-        printf(
-            "%d,%d,%ld,%u,%ld,%u,%ld\n",
-            i % TILE_COLS,
-            i / TILE_COLS,
-            tile.createTime,
-            tile.modifyCount,
-            tile.modifyTime,
-            tile.accessCount,
-            tile.accessTime
-        );
-    }
+		printf(
+			"%d,%d,%ld,%u,%ld,%u,%ld\n",
+			i % TILE_COLS,
+			i / TILE_COLS,
+			tile.createTime,
+			tile.modifyCount,
+			tile.modifyTime,
+			tile.accessCount,
+			tile.accessTime
+		);
+	}
 }
diff --git a/server.c b/server.c
index 749153a..b7970bf 100644
--- a/server.c
+++ b/server.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, June 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
@@ -38,337 +38,337 @@
 static struct Tile *tiles;
 
 static void tilesMap(void) {
-    int fd = open("torus.dat", O_CREAT | O_RDWR, 0644);
-    if (fd < 0) err(EX_CANTCREAT, "torus.dat");
+	int fd = open("torus.dat", O_CREAT | O_RDWR, 0644);
+	if (fd < 0) err(EX_CANTCREAT, "torus.dat");
 
-    int error = ftruncate(fd, TILES_SIZE);
-    if (error) err(EX_IOERR, "ftruncate");
+	int error = ftruncate(fd, TILES_SIZE);
+	if (error) err(EX_IOERR, "ftruncate");
 
-    tiles = mmap(NULL, TILES_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if (tiles == MAP_FAILED) err(EX_OSERR, "mmap");
+	tiles = mmap(NULL, TILES_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if (tiles == MAP_FAILED) err(EX_OSERR, "mmap");
 
-    error = madvise(tiles, TILES_SIZE, MADV_RANDOM);
-    if (error) err(EX_OSERR, "madvise");
+	error = madvise(tiles, TILES_SIZE, MADV_RANDOM);
+	if (error) err(EX_OSERR, "madvise");
 
 #ifdef MADV_NOCORE
-    error = madvise(tiles, TILES_SIZE, MADV_NOCORE);
-    if (error) err(EX_OSERR, "madvise");
+	error = madvise(tiles, TILES_SIZE, MADV_NOCORE);
+	if (error) err(EX_OSERR, "madvise");
 #endif
 }
 
 static struct Tile *tileGet(uint32_t tileX, uint32_t tileY) {
-    struct Tile *tile = &tiles[tileY * TILE_ROWS + tileX];
-    if (!tile->createTime) {
-        memset(tile->cells, ' ', CELLS_SIZE);
-        memset(tile->colors, COLOR_WHITE, CELLS_SIZE);
-        tile->createTime = time(NULL);
-    }
-    return tile;
+	struct Tile *tile = &tiles[tileY * TILE_ROWS + tileX];
+	if (!tile->createTime) {
+		memset(tile->cells, ' ', CELLS_SIZE);
+		memset(tile->colors, COLOR_WHITE, CELLS_SIZE);
+		tile->createTime = time(NULL);
+	}
+	return tile;
 }
 
 static struct Tile *tileAccess(uint32_t tileX, uint32_t tileY) {
-    struct Tile *tile = tileGet(tileX, tileY);
-    tile->accessTime = time(NULL);
-    tile->accessCount++;
-    return tile;
+	struct Tile *tile = tileGet(tileX, tileY);
+	tile->accessTime = time(NULL);
+	tile->accessCount++;
+	return tile;
 }
 
 static struct Tile *tileModify(uint32_t tileX, uint32_t tileY) {
-    struct Tile *tile = tileGet(tileX, tileY);
-    tile->modifyTime = time(NULL);
-    tile->modifyCount++;
-    return tile;
+	struct Tile *tile = tileGet(tileX, tileY);
+	tile->modifyTime = time(NULL);
+	tile->modifyCount++;
+	return tile;
 }
 
 static struct Client {
-    int fd;
+	int fd;
 
-    uint32_t tileX;
-    uint32_t tileY;
-    uint8_t cellX;
-    uint8_t cellY;
+	uint32_t tileX;
+	uint32_t tileY;
+	uint8_t cellX;
+	uint8_t cellY;
 
-    struct Client *prev;
-    struct Client *next;
+	struct Client *prev;
+	struct Client *next;
 } *clientHead;
 
 static struct Client *clientAdd(int fd) {
-    struct Client *client = malloc(sizeof(*client));
-    if (!client) err(EX_OSERR, "malloc");
-
-    client->fd = fd;
-    client->tileX = TILE_VOID_X;
-    client->tileY = TILE_VOID_Y;
-    client->cellX = CELL_INIT_X;
-    client->cellY = CELL_INIT_Y;
-
-    client->prev = NULL;
-    if (clientHead) {
-        clientHead->prev = client;
-        client->next = clientHead;
-    } else {
-        client->next = NULL;
-    }
-    clientHead = client;
-
-    return client;
+	struct Client *client = malloc(sizeof(*client));
+	if (!client) err(EX_OSERR, "malloc");
+
+	client->fd = fd;
+	client->tileX = TILE_VOID_X;
+	client->tileY = TILE_VOID_Y;
+	client->cellX = CELL_INIT_X;
+	client->cellY = CELL_INIT_Y;
+
+	client->prev = NULL;
+	if (clientHead) {
+		clientHead->prev = client;
+		client->next = clientHead;
+	} else {
+		client->next = NULL;
+	}
+	clientHead = client;
+
+	return client;
 }
 
 static bool clientSend(const struct Client *client, struct ServerMessage msg) {
-    ssize_t size = send(client->fd, &msg, sizeof(msg), 0);
-    if (size < 0) return false;
+	ssize_t size = send(client->fd, &msg, sizeof(msg), 0);
+	if (size < 0) return false;
 
-    if (msg.type == SERVER_TILE) {
-        struct Tile *tile = tileAccess(client->tileX, client->tileY);
-        size = send(client->fd, tile, sizeof(*tile), 0);
-        if (size < 0) return false;
-    }
+	if (msg.type == SERVER_TILE) {
+		struct Tile *tile = tileAccess(client->tileX, client->tileY);
+		size = send(client->fd, tile, sizeof(*tile), 0);
+		if (size < 0) return false;
+	}
 
-    return true;
+	return true;
 }
 
 static void clientCast(const struct Client *origin, struct ServerMessage msg) {
-    for (struct Client *client = clientHead; client; client = client->next) {
-        if (client == origin) continue;
-        if (client->tileX != origin->tileX) continue;
-        if (client->tileY != origin->tileY) continue;
-        clientSend(client, msg);
-    }
+	for (struct Client *client = clientHead; client; client = client->next) {
+		if (client == origin) continue;
+		if (client->tileX != origin->tileX) continue;
+		if (client->tileY != origin->tileY) continue;
+		clientSend(client, msg);
+	}
 }
 
 static void clientRemove(struct Client *client) {
-    if (client->prev) client->prev->next = client->next;
-    if (client->next) client->next->prev = client->prev;
-    if (clientHead == client) clientHead = client->next;
-
-    struct ServerMessage msg = {
-        .type = SERVER_CURSOR,
-        .cursor = {
-            .oldCellX = client->cellX, .oldCellY = client->cellY,
-            .newCellX = CURSOR_NONE,   .newCellY = CURSOR_NONE,
-        },
-    };
-    clientCast(client, msg);
-
-    close(client->fd);
-    free(client);
+	if (client->prev) client->prev->next = client->next;
+	if (client->next) client->next->prev = client->prev;
+	if (clientHead == client) clientHead = client->next;
+
+	struct ServerMessage msg = {
+		.type = SERVER_CURSOR,
+		.cursor = {
+			.oldCellX = client->cellX, .oldCellY = client->cellY,
+			.newCellX = CURSOR_NONE,   .newCellY = CURSOR_NONE,
+		},
+	};
+	clientCast(client, msg);
+
+	close(client->fd);
+	free(client);
 }
 
 static bool clientCursors(const struct Client *client) {
-    struct ServerMessage msg = {
-        .type = SERVER_CURSOR,
-        .cursor = { .oldCellX = CURSOR_NONE, .oldCellY = CURSOR_NONE },
-    };
-
-    for (struct Client *friend = clientHead; friend; friend = friend->next) {
-        if (friend == client) continue;
-        if (friend->tileX != client->tileX) continue;
-        if (friend->tileY != client->tileY) continue;
-
-        msg.cursor.newCellX = friend->cellX;
-        msg.cursor.newCellY = friend->cellY;
-        if (!clientSend(client, msg)) return false;
-    }
-    return true;
+	struct ServerMessage msg = {
+		.type = SERVER_CURSOR,
+		.cursor = { .oldCellX = CURSOR_NONE, .oldCellY = CURSOR_NONE },
+	};
+
+	for (struct Client *friend = clientHead; friend; friend = friend->next) {
+		if (friend == client) continue;
+		if (friend->tileX != client->tileX) continue;
+		if (friend->tileY != client->tileY) continue;
+
+		msg.cursor.newCellX = friend->cellX;
+		msg.cursor.newCellY = friend->cellY;
+		if (!clientSend(client, msg)) return false;
+	}
+	return true;
 }
 
 static bool clientUpdate(const struct Client *client, const struct Client *old) {
-    struct ServerMessage msg = {
-        .type = SERVER_MOVE,
-        .move = { .cellX = client->cellX, .cellY = client->cellY },
-    };
-    if (!clientSend(client, msg)) return false;
-
-    if (client->tileX != old->tileX || client->tileY != old->tileY) {
-        msg.type = SERVER_TILE;
-        if (!clientSend(client, msg)) return false;
-
-        if (!clientCursors(client)) return false;
-
-        msg = (struct ServerMessage) {
-            .type = SERVER_CURSOR,
-            .cursor = {
-                .oldCellX = old->cellX,  .oldCellY = old->cellY,
-                .newCellX = CURSOR_NONE, .newCellY = CURSOR_NONE,
-            },
-        };
-        clientCast(old, msg);
-
-        msg = (struct ServerMessage) {
-            .type = SERVER_CURSOR,
-            .cursor = {
-                .oldCellX = CURSOR_NONE,   .oldCellY = CURSOR_NONE,
-                .newCellX = client->cellX, .newCellY = client->cellY,
-            },
-        };
-        clientCast(client, msg);
-
-    } else {
-        msg = (struct ServerMessage) {
-            .type = SERVER_CURSOR,
-            .cursor = {
-                .oldCellX = old->cellX,    .oldCellY = old->cellY,
-                .newCellX = client->cellX, .newCellY = client->cellY,
-            },
-        };
-        clientCast(client, msg);
-    }
-
-    return true;
+	struct ServerMessage msg = {
+		.type = SERVER_MOVE,
+		.move = { .cellX = client->cellX, .cellY = client->cellY },
+	};
+	if (!clientSend(client, msg)) return false;
+
+	if (client->tileX != old->tileX || client->tileY != old->tileY) {
+		msg.type = SERVER_TILE;
+		if (!clientSend(client, msg)) return false;
+
+		if (!clientCursors(client)) return false;
+
+		msg = (struct ServerMessage) {
+			.type = SERVER_CURSOR,
+			.cursor = {
+				.oldCellX = old->cellX,  .oldCellY = old->cellY,
+				.newCellX = CURSOR_NONE, .newCellY = CURSOR_NONE,
+			},
+		};
+		clientCast(old, msg);
+
+		msg = (struct ServerMessage) {
+			.type = SERVER_CURSOR,
+			.cursor = {
+				.oldCellX = CURSOR_NONE,   .oldCellY = CURSOR_NONE,
+				.newCellX = client->cellX, .newCellY = client->cellY,
+			},
+		};
+		clientCast(client, msg);
+
+	} else {
+		msg = (struct ServerMessage) {
+			.type = SERVER_CURSOR,
+			.cursor = {
+				.oldCellX = old->cellX,    .oldCellY = old->cellY,
+				.newCellX = client->cellX, .newCellY = client->cellY,
+			},
+		};
+		clientCast(client, msg);
+	}
+
+	return true;
 }
 
 static bool clientSpawn(struct Client *client, uint8_t spawn) {
-    if (spawn >= SPAWNS_LEN) return false;
-    struct Client old = *client;
-    client->tileX = SPAWNS[spawn].tileX;
-    client->tileY = SPAWNS[spawn].tileY;
-    client->cellX = CELL_INIT_X;
-    client->cellY = CELL_INIT_Y;
-    return clientUpdate(client, &old);
+	if (spawn >= SPAWNS_LEN) return false;
+	struct Client old = *client;
+	client->tileX = SPAWNS[spawn].tileX;
+	client->tileY = SPAWNS[spawn].tileY;
+	client->cellX = CELL_INIT_X;
+	client->cellY = CELL_INIT_Y;
+	return clientUpdate(client, &old);
 }
 
 static bool clientMove(struct Client *client, int8_t dx, int8_t dy) {
-    struct Client old = *client;
-
-    if (dx > CELL_COLS - client->cellX) dx = CELL_COLS - client->cellX;
-    if (dx < -client->cellX - 1)        dx = -client->cellX - 1;
-    if (dy > CELL_ROWS - client->cellY) dy = CELL_ROWS - client->cellY;
-    if (dy < -client->cellY - 1)        dy = -client->cellY - 1;
-
-    client->cellX += dx;
-    client->cellY += dy;
-
-    if (client->cellX == CELL_COLS) {
-        client->tileX++;
-        client->cellX = 0;
-    }
-    if (client->cellX == UINT8_MAX) {
-        client->tileX--;
-        client->cellX = CELL_COLS - 1;
-    }
-    if (client->cellY == CELL_ROWS) {
-        client->tileY++;
-        client->cellY = 0;
-    }
-    if (client->cellY == UINT8_MAX) {
-        client->tileY--;
-        client->cellY = CELL_ROWS - 1;
-    }
-
-    if (client->tileX == TILE_COLS)  client->tileX = 0;
-    if (client->tileX == UINT32_MAX) client->tileX = TILE_COLS - 1;
-    if (client->tileY == TILE_ROWS)  client->tileY = 0;
-    if (client->tileY == UINT32_MAX) client->tileY = TILE_ROWS - 1;
-
-    assert(client->cellX < CELL_COLS);
-    assert(client->cellY < CELL_ROWS);
-    assert(client->tileX < TILE_COLS);
-    assert(client->tileY < TILE_ROWS);
-
-    return clientUpdate(client, &old);
+	struct Client old = *client;
+
+	if (dx > CELL_COLS - client->cellX) dx = CELL_COLS - client->cellX;
+	if (dx < -client->cellX - 1)        dx = -client->cellX - 1;
+	if (dy > CELL_ROWS - client->cellY) dy = CELL_ROWS - client->cellY;
+	if (dy < -client->cellY - 1)        dy = -client->cellY - 1;
+
+	client->cellX += dx;
+	client->cellY += dy;
+
+	if (client->cellX == CELL_COLS) {
+		client->tileX++;
+		client->cellX = 0;
+	}
+	if (client->cellX == UINT8_MAX) {
+		client->tileX--;
+		client->cellX = CELL_COLS - 1;
+	}
+	if (client->cellY == CELL_ROWS) {
+		client->tileY++;
+		client->cellY = 0;
+	}
+	if (client->cellY == UINT8_MAX) {
+		client->tileY--;
+		client->cellY = CELL_ROWS - 1;
+	}
+
+	if (client->tileX == TILE_COLS)  client->tileX = 0;
+	if (client->tileX == UINT32_MAX) client->tileX = TILE_COLS - 1;
+	if (client->tileY == TILE_ROWS)  client->tileY = 0;
+	if (client->tileY == UINT32_MAX) client->tileY = TILE_ROWS - 1;
+
+	assert(client->cellX < CELL_COLS);
+	assert(client->cellY < CELL_ROWS);
+	assert(client->tileX < TILE_COLS);
+	assert(client->tileY < TILE_ROWS);
+
+	return clientUpdate(client, &old);
 }
 
 static bool clientPut(const struct Client *client, uint8_t color, char cell) {
-    struct Tile *tile = tileModify(client->tileX, client->tileY);
-    tile->colors[client->cellY][client->cellX] = color;
-    tile->cells[client->cellY][client->cellX] = cell;
-
-    struct ServerMessage msg = {
-        .type = SERVER_PUT,
-        .put = {
-            .cellX = client->cellX,
-            .cellY = client->cellY,
-            .color = color,
-            .cell = cell,
-        },
-    };
-    bool success = clientSend(client, msg);
-    clientCast(client, msg);
-    return success;
+	struct Tile *tile = tileModify(client->tileX, client->tileY);
+	tile->colors[client->cellY][client->cellX] = color;
+	tile->cells[client->cellY][client->cellX] = cell;
+
+	struct ServerMessage msg = {
+		.type = SERVER_PUT,
+		.put = {
+			.cellX = client->cellX,
+			.cellY = client->cellY,
+			.color = color,
+			.cell = cell,
+		},
+	};
+	bool success = clientSend(client, msg);
+	clientCast(client, msg);
+	return success;
 }
 
 int main() {
-    int error;
-
-    tilesMap();
-
-    int server = socket(PF_LOCAL, SOCK_STREAM, 0);
-    if (server < 0) err(EX_OSERR, "socket");
-
-    error = unlink("torus.sock");
-    if (error && errno != ENOENT) err(EX_IOERR, "torus.sock");
-
-    struct sockaddr_un addr = {
-        .sun_family = AF_LOCAL,
-        .sun_path = "torus.sock",
-    };
-    error = bind(server, (struct sockaddr *)&addr, sizeof(addr));
-    if (error) err(EX_CANTCREAT, "torus.sock");
-
-    error = listen(server, 0);
-    if (error) err(EX_OSERR, "listen");
-
-    int kq = kqueue();
-    if (kq < 0) err(EX_OSERR, "kqueue");
-
-    struct kevent event = {
-        .ident = server,
-        .filter = EVFILT_READ,
-        .flags = EV_ADD,
-    };
-    int nevents = kevent(kq, &event, 1, NULL, 0, NULL);
-    if (nevents < 0) err(EX_OSERR, "kevent");
-
-    for (;;) {
-        nevents = kevent(kq, NULL, 0, &event, 1, NULL);
-        if (nevents < 0) err(EX_IOERR, "kevent");
-
-        if (!event.udata) {
-            int fd = accept(server, NULL, NULL);
-            if (fd < 0) err(EX_IOERR, "accept");
-            fcntl(fd, F_SETFL, O_NONBLOCK);
-
-            int on = 1;
-            error = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
-            if (error) err(EX_IOERR, "setsockopt");
-
-            struct Client *client = clientAdd(fd);
-
-            struct kevent event = {
-                .ident = fd,
-                .filter = EVFILT_READ,
-                .flags = EV_ADD,
-                .udata = client,
-            };
-            nevents = kevent(kq, &event, 1, NULL, 0, NULL);
-            if (nevents < 0) err(EX_IOERR, "kevent");
-
-            if (!clientSpawn(client, 0)) clientRemove(client);
-
-            continue;
-        }
-
-        struct Client *client = event.udata;
-        if (event.flags & EV_EOF) {
-            clientRemove(client);
-            continue;
-        }
-
-        struct ClientMessage msg;
-        ssize_t size = recv(client->fd, &msg, sizeof(msg), 0);
-        if (size != sizeof(msg)) {
-            clientRemove(client);
-            continue;
-        }
-
-        bool success = false;
-        if (msg.type == CLIENT_MOVE) {
-            success = clientMove(client, msg.move.dx, msg.move.dy);
-        } else if (msg.type == CLIENT_PUT) {
-            success = clientPut(client, msg.put.color, msg.put.cell);
-        } else if (msg.type == CLIENT_SPAWN) {
-            success = clientSpawn(client, msg.spawn);
-        }
-        if (!success) clientRemove(client);
-    }
+	int error;
+
+	tilesMap();
+
+	int server = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (server < 0) err(EX_OSERR, "socket");
+
+	error = unlink("torus.sock");
+	if (error && errno != ENOENT) err(EX_IOERR, "torus.sock");
+
+	struct sockaddr_un addr = {
+		.sun_family = AF_LOCAL,
+		.sun_path = "torus.sock",
+	};
+	error = bind(server, (struct sockaddr *)&addr, sizeof(addr));
+	if (error) err(EX_CANTCREAT, "torus.sock");
+
+	error = listen(server, 0);
+	if (error) err(EX_OSERR, "listen");
+
+	int kq = kqueue();
+	if (kq < 0) err(EX_OSERR, "kqueue");
+
+	struct kevent event = {
+		.ident = server,
+		.filter = EVFILT_READ,
+		.flags = EV_ADD,
+	};
+	int nevents = kevent(kq, &event, 1, NULL, 0, NULL);
+	if (nevents < 0) err(EX_OSERR, "kevent");
+
+	for (;;) {
+		nevents = kevent(kq, NULL, 0, &event, 1, NULL);
+		if (nevents < 0) err(EX_IOERR, "kevent");
+
+		if (!event.udata) {
+			int fd = accept(server, NULL, NULL);
+			if (fd < 0) err(EX_IOERR, "accept");
+			fcntl(fd, F_SETFL, O_NONBLOCK);
+
+			int on = 1;
+			error = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
+			if (error) err(EX_IOERR, "setsockopt");
+
+			struct Client *client = clientAdd(fd);
+
+			struct kevent event = {
+				.ident = fd,
+				.filter = EVFILT_READ,
+				.flags = EV_ADD,
+				.udata = client,
+			};
+			nevents = kevent(kq, &event, 1, NULL, 0, NULL);
+			if (nevents < 0) err(EX_IOERR, "kevent");
+
+			if (!clientSpawn(client, 0)) clientRemove(client);
+
+			continue;
+		}
+
+		struct Client *client = event.udata;
+		if (event.flags & EV_EOF) {
+			clientRemove(client);
+			continue;
+		}
+
+		struct ClientMessage msg;
+		ssize_t size = recv(client->fd, &msg, sizeof(msg), 0);
+		if (size != sizeof(msg)) {
+			clientRemove(client);
+			continue;
+		}
+
+		bool success = false;
+		if (msg.type == CLIENT_MOVE) {
+			success = clientMove(client, msg.move.dx, msg.move.dy);
+		} else if (msg.type == CLIENT_PUT) {
+			success = clientPut(client, msg.put.color, msg.put.cell);
+		} else if (msg.type == CLIENT_SPAWN) {
+			success = clientSpawn(client, msg.spawn);
+		}
+		if (!success) clientRemove(client);
+	}
 }
diff --git a/sshd_config b/sshd_config
index 9e48107..2d4366a 100644
--- a/sshd_config
+++ b/sshd_config
@@ -1,13 +1,13 @@
 UsePAM no
 
 Match User torus
-    PasswordAuthentication yes
-    PermitEmptyPasswords yes
-    ChrootDirectory /home/torus
-    ForceCommand client
+	PasswordAuthentication yes
+	PermitEmptyPasswords yes
+	ChrootDirectory /home/torus
+	ForceCommand client
 
-    AllowAgentForwarding no
-    AllowTcpForwarding no
-    AllowStreamLocalForwarding no
-    MaxSessions 1
-    X11Forwarding no
+	AllowAgentForwarding no
+	AllowTcpForwarding no
+	AllowStreamLocalForwarding no
+	MaxSessions 1
+	X11Forwarding no
diff --git a/torus.h b/torus.h
index 5e01aaa..3538213 100644
--- a/torus.h
+++ b/torus.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, June 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
@@ -34,20 +34,20 @@
 #undef COLOR_WHITE
 
 enum {
-    COLOR_BLACK,
-    COLOR_RED,
-    COLOR_GREEN,
-    COLOR_YELLOW,
-    COLOR_BLUE,
-    COLOR_MAGENTA,
-    COLOR_CYAN,
-    COLOR_WHITE,
-    COLOR_BRIGHT,
+	COLOR_BLACK,
+	COLOR_RED,
+	COLOR_GREEN,
+	COLOR_YELLOW,
+	COLOR_BLUE,
+	COLOR_MAGENTA,
+	COLOR_CYAN,
+	COLOR_WHITE,
+	COLOR_BRIGHT,
 };
 
 enum {
-    CELL_ROWS = 25,
-    CELL_COLS = 80,
+	CELL_ROWS = 25,
+	CELL_COLS = 80,
 };
 static const size_t CELLS_SIZE = sizeof(char[CELL_ROWS][CELL_COLS]);
 
@@ -55,21 +55,21 @@ static const uint8_t CELL_INIT_X = CELL_COLS / 2;
 static const uint8_t CELL_INIT_Y = CELL_ROWS / 2;
 
 struct ALIGNED(4096) Tile {
-    time_t createTime;
-    time_t modifyTime;
-    char ALIGNED(16) cells[CELL_ROWS][CELL_COLS];
-    uint8_t ALIGNED(16) colors[CELL_ROWS][CELL_COLS];
-    uint32_t modifyCount;
-    uint32_t accessCount;
-    time_t accessTime;
+	time_t createTime;
+	time_t modifyTime;
+	char ALIGNED(16) cells[CELL_ROWS][CELL_COLS];
+	uint8_t ALIGNED(16) colors[CELL_ROWS][CELL_COLS];
+	uint32_t modifyCount;
+	uint32_t accessCount;
+	time_t accessTime;
 };
-static_assert(4096 == sizeof(struct Tile), "struct File is page-sized");
+static_assert(4096 == sizeof(struct Tile), "struct Tile is page-sized");
 static_assert(16 == offsetof(struct Tile, cells), "stable cells offset");
 static_assert(2016 == offsetof(struct Tile, colors), "stable colors offset");
 
 enum {
-    TILE_ROWS = 512,
-    TILE_COLS = 512,
+	TILE_ROWS = 512,
+	TILE_COLS = 512,
 };
 static const size_t TILES_SIZE = sizeof(struct Tile[TILE_ROWS][TILE_COLS]);
 
@@ -77,61 +77,61 @@ static const uint32_t TILE_VOID_X = UINT32_MAX;
 static const uint32_t TILE_VOID_Y = UINT32_MAX;
 
 static const struct {
-    uint32_t tileX;
-    uint32_t tileY;
+	uint32_t tileX;
+	uint32_t tileY;
 } SPAWNS[] = {
-    { 0, 0 },
-    { TILE_COLS * 3 / 4, TILE_ROWS * 3 / 4 }, // NW
-    { TILE_COLS * 1 / 4, TILE_ROWS * 3 / 4 }, // NE
-    { TILE_COLS * 1 / 4, TILE_ROWS * 1 / 4 }, // SE
-    { TILE_COLS * 3 / 4, TILE_ROWS * 1 / 4 }, // SW
+	{ 0, 0 },
+	{ TILE_COLS * 3 / 4, TILE_ROWS * 3 / 4 }, // NW
+	{ TILE_COLS * 1 / 4, TILE_ROWS * 3 / 4 }, // NE
+	{ TILE_COLS * 1 / 4, TILE_ROWS * 1 / 4 }, // SE
+	{ TILE_COLS * 3 / 4, TILE_ROWS * 1 / 4 }, // SW
 };
 static const size_t SPAWNS_LEN = sizeof(SPAWNS) / sizeof(SPAWNS[0]);
 
 struct ServerMessage {
-    enum PACKED {
-        SERVER_TILE,
-        SERVER_MOVE,
-        SERVER_PUT,
-        SERVER_CURSOR,
-    } type;
-    union {
-        struct {
-            uint8_t cellX;
-            uint8_t cellY;
-        } move;
-        struct {
-            uint8_t cellX;
-            uint8_t cellY;
-            uint8_t color;
-            char cell;
-        } put;
-        struct {
-            uint8_t oldCellX;
-            uint8_t oldCellY;
-            uint8_t newCellX;
-            uint8_t newCellY;
-        } cursor;
-    };
+	enum PACKED {
+		SERVER_TILE,
+		SERVER_MOVE,
+		SERVER_PUT,
+		SERVER_CURSOR,
+	} type;
+	union {
+		struct {
+			uint8_t cellX;
+			uint8_t cellY;
+		} move;
+		struct {
+			uint8_t cellX;
+			uint8_t cellY;
+			uint8_t color;
+			char cell;
+		} put;
+		struct {
+			uint8_t oldCellX;
+			uint8_t oldCellY;
+			uint8_t newCellX;
+			uint8_t newCellY;
+		} cursor;
+	};
 };
 
 static const uint8_t CURSOR_NONE = UINT8_MAX;
 
 struct ClientMessage {
-    enum PACKED {
-        CLIENT_MOVE,
-        CLIENT_PUT,
-        CLIENT_SPAWN,
-    } type;
-    union {
-        struct {
-            int8_t dx;
-            int8_t dy;
-        } move;
-        struct {
-            uint8_t color;
-            char cell;
-        } put;
-        uint8_t spawn;
-    };
+	enum PACKED {
+		CLIENT_MOVE,
+		CLIENT_PUT,
+		CLIENT_SPAWN,
+	} type;
+	union {
+		struct {
+			int8_t dx;
+			int8_t dy;
+		} move;
+		struct {
+			uint8_t color;
+			char cell;
+		} put;
+		uint8_t spawn;
+	};
 };