eb8499f35b
fix conic tests
2025-06-25 19:16:06 +01:00
3a6d5c0005
merge main and modeling-api
2025-06-25 18:01:04 +01:00
e1ab6bbc48
Swap "must" for "should" in identifier casing lint ( #7604 )
...
Draft: Swap "must" for "should" in identifier casing lint
2025-06-25 12:48:02 -04:00
67122d66e0
Remove commented code
2025-06-25 12:30:27 -04:00
d3d2349a80
Remove from operations for now until we have icons
2025-06-25 12:21:03 -04:00
0a1f35b89a
Release KCL 83 ( #7603 )
2025-06-25 10:42:57 -04:00
6f1a539e83
Error on non-count indexing ( #7539 )
...
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-25 20:36:57 +12:00
9f34c0d0c0
Fix clippy lints
2025-06-24 18:52:09 -04:00
dc0c5d5278
Fix formatting errors
2025-06-24 18:52:09 -04:00
7b490da1b4
Run rustfmt
2025-06-24 18:43:32 -04:00
c7f0a6c2a0
Upgrade to ts-rs 11.0 for TS type fixes ( #7581 )
...
* Bump ts-rs from 10.1.0 to 11.0.1
* Fix breaking changes
* Fix tsc errors
* Update output
* Upgrade to kittycad-modeling-cmds 0.2.124 for ts-rs update
* Update parser snaps
* Update output of gridfinity_bins_stacking_lip sample
* Fix missing field in TS unit tests
* Fix tsc type error with fixed_size_grid project setting
2025-06-24 18:38:43 +00:00
e4941cb524
Fix quote escaping in docs ( #7594 )
2025-06-24 17:43:43 +00:00
1b687a82a6
Update stdlib docs output to match main ( #7593 )
...
* Update sim test output to match main
* Update stdlib docs
2025-06-24 12:44:28 -04:00
478bf34f2b
Coordinate grid uses same scale as user's units ( #7465 )
...
Closes https://github.com/KittyCAD/engine/issues/3494 . Thanks to @nadr0 for helping on the JS side.
If users set their units, the grid will stop auto scaling, and instead will be set to 10 of whatever unit they used.
If users set their units, and those units are metric, then it'll include a scale bar (see screenshot). Imperial units won't have that bar.
This behaviour is configurable via settings.
## Limitations
- The scale bar below the grid cannot be disabled in metric units, and cannot be enabled in imperial units
<img width="1690" alt="Screenshot 2025-06-05 at 7 51 41 PM" src="https://github.com/user-attachments/assets/c597087c-f96d-4c30-95f4-b3d8ba2b5567 " />
2025-06-23 17:30:26 -05:00
1e1bdbd6e7
use face edge info for some mirrors ( #7174 )
...
* use face edge info for some mirrors
* add functionality for other mirror function
* Fix to create new Sketch when mirror results in a new path
* use the original ids and clone the sketches
* remove mirror param
* clippy fix
* debuggin, rm yarn
* Revert "remove mirror param"
This reverts commit a848e243f8
.
* use arrbitrary edge_id as sketch mirror id
* additinoal clenaup
* Update rust/kcl-lib/src/std/mirror.rs
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
* set .mirror for continuous case
* fix warning
* works without the for loops
* add error handling
* remove duplicate setter
* rm unused var
* clenaup
* unused import
* remove unused let
* Update snapshots
* Update snapshots
* cleanup
* update sim tests
---------
Co-authored-by: gserena <serena@zoo.dev >
Co-authored-by: Jonathan Tran <jonnytran@gmail.com >
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-23 12:27:03 -05:00
eabcf86436
Add building the artifact graph in sketch mode, take 2 ( #7557 )
...
* Add building the artifact graph in mock execution
* Update output
* Add updating the artifact graph after mock execution
* Fix spelling
* Fix to return it all the way
* Fix to not make artifact fields undefined in TS
2025-06-23 15:34:14 +00:00
5f2a10ec7e
docs: Add better docs for tolerance parameter ( #7548 )
...
* Add better docs for tolerance parameter
* Update generated docs
2025-06-20 11:42:14 -04:00
eeaa71142a
Convert units of tolerance for CSG functions ( #7540 )
...
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-20 07:14:30 +12:00
9dd6e3e852
KCL: Support non-ASCII identifiers ( #7525 )
...
Both human and LLMs want to write KCL code in non-English languages. This is important and we should support it.
Note that errors are currently a bit broken with non-ASCII identifiers, see #4327
2025-06-19 14:10:21 +00:00
9eaacc2a51
KCL: involuteCircular can use diameter in addition to radius ( #7519 )
...
Mechanical engineers prefer using diameter over radius.
2025-06-19 14:09:24 +00:00
37e9e9015a
Merge remote-tracking branch 'origin/main' into ben/conics
2025-06-19 11:21:15 +01:00
6358eed7e4
Release KCL 82 ( #7531 )
2025-06-19 01:03:13 +00:00
3fea2efd81
update to new exec_state.batch
2025-06-18 13:32:32 +01:00
96eebc3d27
merge main
2025-06-18 12:09:02 +01:00
0c702e4bab
Use nightly rustfmt in CI ( #7509 )
...
* Use nightly rustfmt in CI
* Fix current code to be nightly formatted
2025-06-17 18:30:33 +00:00
b2152a5684
Bump the minor group across 1 directory with 25 updates ( #7491 )
...
* Bump the minor group across 1 directory with 25 updates
Bumps the minor group with 25 updates in the /rust directory:
| Package | From | To |
| --- | --- | --- |
| [bson](https://github.com/mongodb/bson-rust ) | `2.14.0` | `2.15.0` |
| [clap](https://github.com/clap-rs/clap ) | `4.5.36` | `4.5.40` |
| [miette](https://github.com/zkat/miette ) | `7.5.0` | `7.6.0` |
| [pyo3](https://github.com/pyo3/pyo3 ) | `0.24.1` | `0.24.2` |
| [tokio](https://github.com/tokio-rs/tokio ) | `1.44.2` | `1.45.1` |
| [uuid](https://github.com/uuid-rs/uuid ) | `1.16.0` | `1.17.0` |
| [toml_edit](https://github.com/toml-rs/toml ) | `0.22.24` | `0.22.26` |
| [proc-macro2](https://github.com/dtolnay/proc-macro2 ) | `1.0.94` | `1.0.95` |
| [syn](https://github.com/dtolnay/syn ) | `2.0.100` | `2.0.103` |
| [signal-hook](https://github.com/vorner/signal-hook ) | `0.3.17` | `0.3.18` |
| [flate2](https://github.com/rust-lang/flate2-rs ) | `1.1.1` | `1.1.2` |
| [chrono](https://github.com/chronotope/chrono ) | `0.4.40` | `0.4.41` |
| [itertools](https://github.com/rust-itertools/itertools ) | `0.13.0` | `0.14.0` |
| [reqwest](https://github.com/seanmonstar/reqwest ) | `0.12.15` | `0.12.20` |
| [sha2](https://github.com/RustCrypto/hashes ) | `0.10.8` | `0.10.9` |
| [tabled](https://github.com/zhiburt/tabled ) | `0.18.0` | `0.20.0` |
| [tempfile](https://github.com/Stebalien/tempfile ) | `3.19.0` | `3.20.0` |
| [toml](https://github.com/toml-rs/toml ) | `0.8.20` | `0.8.22` |
| [tynm](https://github.com/azriel91/tynm ) | `0.1.10` | `0.2.0` |
| [winnow](https://github.com/winnow-rs/winnow ) | `0.7.10` | `0.7.11` |
| [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite ) | `0.26.2` | `0.27.0` |
| [expectorate](https://github.com/oxidecomputer/expectorate ) | `1.1.0` | `1.2.0` |
| [insta](https://github.com/mitsuhiko/insta ) | `1.42.2` | `1.43.1` |
| [twenty-twenty](https://github.com/kittycad/twenty-twenty ) | `0.8.1` | `0.8.2` |
| [data-encoding](https://github.com/ia0/data-encoding ) | `2.8.0` | `2.9.0` |
Updates `bson` from 2.14.0 to 2.15.0
- [Release notes](https://github.com/mongodb/bson-rust/releases )
- [Commits](https://github.com/mongodb/bson-rust/compare/v2.14.0...v2.15.0 )
Updates `clap` from 4.5.36 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases )
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md )
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.36...clap_complete-v4.5.40 )
Updates `miette` from 7.5.0 to 7.6.0
- [Release notes](https://github.com/zkat/miette/releases )
- [Changelog](https://github.com/zkat/miette/blob/main/CHANGELOG.md )
- [Commits](https://github.com/zkat/miette/commits/miette-derive-v7.6.0 )
Updates `pyo3` from 0.24.1 to 0.24.2
- [Release notes](https://github.com/pyo3/pyo3/releases )
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md )
- [Commits](https://github.com/pyo3/pyo3/compare/v0.24.1...v0.24.2 )
Updates `tokio` from 1.44.2 to 1.45.1
- [Release notes](https://github.com/tokio-rs/tokio/releases )
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.44.2...tokio-1.45.1 )
Updates `uuid` from 1.16.0 to 1.17.0
- [Release notes](https://github.com/uuid-rs/uuid/releases )
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.16.0...v1.17.0 )
Updates `toml_edit` from 0.22.24 to 0.22.26
- [Commits](https://github.com/toml-rs/toml/compare/v0.22.24...v0.22.26 )
Updates `proc-macro2` from 1.0.94 to 1.0.95
- [Release notes](https://github.com/dtolnay/proc-macro2/releases )
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.94...1.0.95 )
Updates `syn` from 2.0.100 to 2.0.103
- [Release notes](https://github.com/dtolnay/syn/releases )
- [Commits](https://github.com/dtolnay/syn/compare/2.0.100...2.0.103 )
Updates `signal-hook` from 0.3.17 to 0.3.18
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md )
- [Commits](https://github.com/vorner/signal-hook/compare/v0.3.17...v0.3.18 )
Updates `flate2` from 1.1.1 to 1.1.2
- [Release notes](https://github.com/rust-lang/flate2-rs/releases )
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.1...1.1.2 )
Updates `chrono` from 0.4.40 to 0.4.41
- [Release notes](https://github.com/chronotope/chrono/releases )
- [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md )
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.40...v0.4.41 )
Updates `itertools` from 0.13.0 to 0.14.0
- [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md )
- [Commits](https://github.com/rust-itertools/itertools/compare/v0.13.0...v0.14.0 )
Updates `reqwest` from 0.12.15 to 0.12.20
- [Release notes](https://github.com/seanmonstar/reqwest/releases )
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md )
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.15...v0.12.20 )
Updates `sha2` from 0.10.8 to 0.10.9
- [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.8...sha2-v0.10.9 )
Updates `tabled` from 0.18.0 to 0.20.0
- [Changelog](https://github.com/zhiburt/tabled/blob/master/CHANGELOG.md )
- [Commits](https://github.com/zhiburt/tabled/commits )
Updates `tempfile` from 3.19.0 to 3.20.0
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md )
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.19.0...v3.20.0 )
Updates `toml` from 0.8.20 to 0.8.22
- [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.20...toml-v0.8.22 )
Updates `tynm` from 0.1.10 to 0.2.0
- [Release notes](https://github.com/azriel91/tynm/releases )
- [Changelog](https://github.com/azriel91/tynm/blob/main/CHANGELOG.md )
- [Commits](https://github.com/azriel91/tynm/compare/0.1.10...0.2.0 )
Updates `winnow` from 0.7.10 to 0.7.11
- [Changelog](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md )
- [Commits](https://github.com/winnow-rs/winnow/compare/v0.7.10...v0.7.11 )
Updates `tokio-tungstenite` from 0.26.2 to 0.27.0
- [Changelog](https://github.com/snapview/tokio-tungstenite/blob/master/CHANGELOG.md )
- [Commits](https://github.com/snapview/tokio-tungstenite/compare/v0.26.2...v0.27.0 )
Updates `expectorate` from 1.1.0 to 1.2.0
- [Release notes](https://github.com/oxidecomputer/expectorate/releases )
- [Commits](https://github.com/oxidecomputer/expectorate/compare/v1.1.0...v1.2.0 )
Updates `insta` from 1.42.2 to 1.43.1
- [Release notes](https://github.com/mitsuhiko/insta/releases )
- [Changelog](https://github.com/mitsuhiko/insta/blob/master/CHANGELOG.md )
- [Commits](https://github.com/mitsuhiko/insta/compare/1.42.2...1.43.1 )
Updates `twenty-twenty` from 0.8.1 to 0.8.2
- [Release notes](https://github.com/kittycad/twenty-twenty/releases )
- [Commits](https://github.com/kittycad/twenty-twenty/commits/v0.8.2 )
Updates `data-encoding` from 2.8.0 to 2.9.0
- [Commits](https://github.com/ia0/data-encoding/compare/v2.8.0...v2.9.0 )
---
updated-dependencies:
- dependency-name: bson
dependency-version: 2.15.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: clap
dependency-version: 4.5.40
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: miette
dependency-version: 7.6.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: pyo3
dependency-version: 0.24.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: tokio
dependency-version: 1.45.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: uuid
dependency-version: 1.17.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: toml_edit
dependency-version: 0.22.26
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: proc-macro2
dependency-version: 1.0.95
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: syn
dependency-version: 2.0.103
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: signal-hook
dependency-version: 0.3.18
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: flate2
dependency-version: 1.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: chrono
dependency-version: 0.4.41
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: itertools
dependency-version: 0.14.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: reqwest
dependency-version: 0.12.20
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: sha2
dependency-version: 0.10.9
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: tabled
dependency-version: 0.20.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: tempfile
dependency-version: 3.20.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: toml
dependency-version: 0.8.22
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: tynm
dependency-version: 0.2.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: winnow
dependency-version: 0.7.11
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: tokio-tungstenite
dependency-version: 0.27.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: expectorate
dependency-version: 1.2.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: insta
dependency-version: 1.43.1
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
- dependency-name: twenty-twenty
dependency-version: 0.8.2
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor
- dependency-name: data-encoding
dependency-version: 2.9.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor
...
Signed-off-by: dependabot[bot] <support@github.com >
* Update snapshots
* Update snapshots
---------
Signed-off-by: dependabot[bot] <support@github.com >
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-17 05:29:38 -04:00
7486d25cf1
Change KCL stdlib floating-point results to not be platform dependent ( #7499 )
...
* Add libm dependency
* Change to use libm for trig functions
* Remove redactions for floating point
* Update output
* Use clippy to prevent stdlib math sneaking back in
---------
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev >
2025-06-17 01:34:50 +00:00
1a4a030671
Properly respect associativity when reformatting ( #7486 )
...
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-17 11:10:37 +12:00
ad9822e8ac
Change to use web-time instead of unmaintained instant crate ( #7497 )
2025-06-16 16:36:05 -04:00
aae34cf1e5
Deterministic artifact graph - bring back the clockwork universe ( #7483 )
...
* Change to use deterministic artifact graph
* Update output to use the new order
* Fix to clear everything when scene is cleared
* Fix lots
* Update artifact graph output for the last time
* Delete unused sorting code
* Remove unneeded cfg
* Fix to preserve top-level artifacts when there's an error
* Update output after error fix
* Add better doc comments
* Remove duplicate global operations
* Update comments
* Update ignored tests that were flaky
* Update graph for new samples after rebase
* Fix test assertion message
2025-06-16 17:55:24 +00:00
d6278cf075
KCL: change twist to a case of extrude ( #7481 )
...
@franknoirot @jtran and I decided that the `extrudeTwist()` function (which I added in https://github.com/KittyCAD/modeling-app/pull/7480 ) would be better as an optional case of the normal `extrude` function. Doing it this way means less work for the frontend team.
2025-06-16 16:35:30 +00:00
3936017f10
Tag types ( #7458 )
...
* Replace tag type with tagIdent and tagDecl
Signed-off-by: Nick Cameron <nrc@ncameron.org >
* Replace tagIdent with TaggedEdge and TaggedFace
Signed-off-by: Nick Cameron <nrc@ncameron.org >
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-16 09:10:36 +12:00
2b0ced179a
Add files via upload ( #7429 )
...
* Add files via upload
* Update snapshots
* Update snapshots
* Update snapshots
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jace Browning <jacebrowning@gmail.com >
2025-06-14 02:27:27 +00:00
c2f6ce065d
KCL: New extrudeTwist endpoint ( #7480 )
...
This does not include feature tree editing support.
2025-06-13 21:17:01 +00:00
c6b1d11700
Fix to not panic when using the wrong argument type ( #7474 )
2025-06-13 14:02:14 -04:00
939c2c77b0
the settings docs have a stutter with 2 h1s this fixes it ( #7472 )
...
* the settings docs have a stutter with 2 h1s this fixes it
Signed-off-by: Jessie Frazelle <github@jessfraz.com >
* regenerate
Signed-off-by: Jessie Frazelle <github@jessfraz.com >
---------
Signed-off-by: Jessie Frazelle <github@jessfraz.com >
2025-06-13 16:33:28 +10:00
383b38c2d2
Add operations for variable declarations ( #7451 )
...
* Add operations for variable declarations
* Update output
* Change to use OpKclValue
* Update output after merge
2025-06-12 16:38:12 +00:00
e0025f7fad
Release KCL 81 ( #7463 )
2025-06-12 16:20:41 +00:00
1443f3ab39
Improve error messages around PI and other numbers with unknown units ( #7457 )
...
* Improve docs around PI
Signed-off-by: Nick Cameron <nrc@ncameron.org >
* Refactor and polish type error messages
Signed-off-by: Nick Cameron <nrc@ncameron.org >
* Add suggestion to fix unknown numbers error
Signed-off-by: Nick Cameron <nrc@ncameron.org >
* Don't warn so often about unknown units
Signed-off-by: Nick Cameron <nrc@ncameron.org >
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-12 10:20:04 -04:00
5d23b0e487
add broken tests ( #7445 )
...
* add broken tests
* spelling work around
2025-06-12 11:33:46 +00:00
df6c81b0b4
Units bug fix with modulo ( #7446 )
...
* Add degrees annotations to examples
Signed-off-by: Nick Cameron <nrc@ncameron.org >
* Fix a units bug with the modulo operation
Signed-off-by: Nick Cameron <nrc@ncameron.org >
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-12 08:44:55 +12:00
9a549ff379
Track artifact commands and operations per-module ( #7426 )
...
* Change so that operations are stored per module
* Refactor so that all modeling commands go through ExecState
* Remove unneeded PartialOrd implementations
* Remove artifact_commands from KclError since it was only for debugging
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-11 01:30:48 +00:00
851ea28bd3
Change trig functions to return number with Default units ( #7425 )
...
* Change trig functions to return number with Default units
* Update docs
* Update output
2025-06-11 00:24:48 +00:00
6460ed8ea8
bump the client API response timeout 60 -> 300 ( #7406 )
2025-06-06 16:02:42 -07:00
c4caf1ec94
add absolute points to conic fns
2025-06-06 12:28:51 +01:00
0f51113009
update to latest main
2025-06-06 10:48:26 +01:00
8d4a4b529b
Merge remote-tracking branch 'origin/main' into ben/conics
2025-06-06 10:25:09 +01:00
e116bbaae8
Remove the untyped getters from std::args ( #7377 )
...
* Move last uses of untypeed arg getters
Signed-off-by: Nick Cameron <nrc@ncameron.org >
* Rename _typed functions
Signed-off-by: Nick Cameron <nrc@ncameron.org >
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-05 18:45:58 -04:00
18b458fbca
Fix some typos in previous PR ( #7392 )
...
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-06 10:05:38 +12:00
4d1524f03b
Format examples in docs ( #7378 )
...
Signed-off-by: Nick Cameron <nrc@ncameron.org >
2025-06-05 18:01:45 -04:00