summary refs log tree commit diff
path: root/www/photo.causal.agency
diff options
context:
space:
mode:
Diffstat (limited to 'www/photo.causal.agency')
-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/000054970005.txt3
-rw-r--r--www/photo.causal.agency/2024-08-29/000054970006.txt2
-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/trips.html343
33 files changed, 460 insertions, 0 deletions
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/000054970005.txt b/www/photo.causal.agency/2024-08-29/000054970005.txt
new file mode 100644
index 00000000..89cfbe7f
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-29/000054970005.txt
@@ -0,0 +1,3 @@
+Ayla in an orange sweater
+pulling her fingers through her hair
+and making a squinting face.
diff --git a/www/photo.causal.agency/2024-08-29/000054970006.txt b/www/photo.causal.agency/2024-08-29/000054970006.txt
new file mode 100644
index 00000000..dcf4b50e
--- /dev/null
+++ b/www/photo.causal.agency/2024-08-29/000054970006.txt
@@ -0,0 +1,2 @@
+Ayla in an orange sweater
+looking to the side and smiling.
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/trips.html b/www/photo.causal.agency/trips.html
new file mode 100644
index 00000000..ddad2adb
--- /dev/null
+++ b/www/photo.causal.agency/trips.html
@@ -0,0 +1,343 @@
+<!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>
+<button type="button" onclick="loadRoll()">Load</button>
+</form>
+
+<datalist id="films">
+	<option>Harman Phoenix 200</option>
+	<option>Shanghai Color 400</option>
+	<option>CineStill 800T</option>
+	<option>Ilford HP5 Plus 400</option>
+	<option>Ilford FP4 Plus 125</option>
+	<option>Ilford Delta 100</option>
+	<option>Fomapan Creative 200</option>
+	<option>Fomapan Action 400</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 rollUl = document.createElement("ul");
+		for (let trip of rollTrips) {
+			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}`
+			));
+			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 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) {
+		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;
+	rolls[body] = { id: nextId++, film, used: 0, exposures: 36 };
+	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>