forked from cadey/xesite
Compare commits
288 Commits
using-andr
...
main
Author | SHA1 | Date |
---|---|---|
Cadey Ratio | 33b7dfa21c | |
dependabot[bot] | d7b817b22d | |
Cadey Ratio | 08ccd40888 | |
dependabot[bot] | 3fcbe4ebbf | |
dependabot[bot] | 8759f9d590 | |
dependabot[bot] | b36afa9dfd | |
Cadey Ratio | f91a5a7878 | |
Cadey Ratio | b32f5a25af | |
Cadey Ratio | 18ae8a01f8 | |
Loric Brevet | 04151593cc | |
dependabot[bot] | a6ddd7e3a6 | |
dependabot[bot] | f8dae6fa5e | |
dependabot[bot] | ed1e8eecee | |
dependabot[bot] | 3020a92086 | |
dependabot[bot] | d93bdc58a6 | |
Cadey Ratio | 7f6de2cb09 | |
Cadey Ratio | 8b6056fc09 | |
Cadey Ratio | 5d7daf179e | |
Cadey Ratio | 6be8b24dd2 | |
Cadey Ratio | 03fa2e33a1 | |
dependabot[bot] | bf95a3f7e0 | |
dependabot[bot] | 70b2cc5408 | |
dependabot[bot] | b5b804e083 | |
dependabot[bot] | 7828552cca | |
dependabot[bot] | 000ed82301 | |
Cadey Ratio | 817d426314 | |
Cadey Ratio | 13f28eae67 | |
Cadey Ratio | a1974a5948 | |
Cadey Ratio | 15a130cc3d | |
dependabot[bot] | 9f977b3882 | |
dependabot[bot] | 50dcfbb19d | |
dependabot[bot] | aeab6536e0 | |
bjorn3 | 78485b7d49 | |
dependabot[bot] | cea1e230da | |
Vincent Bernat | 3a592f99db | |
Molly Miller | d0c2df003b | |
Cadey Ratio | ad6fba4c79 | |
Gabriel Simmer | 7541df7781 | |
Cadey Ratio | 5c09a72207 | |
Cadey Ratio | 792be1eb55 | |
Cadey Ratio | aa10dce9ee | |
Cadey Ratio | aca8b80892 | |
Cadey Ratio | dc3f6471e7 | |
Cadey Ratio | 396150f72b | |
dependabot[bot] | 2645966f85 | |
dependabot[bot] | 7d667ef2ae | |
Jade Lovelace | 7bf1f82c90 | |
dependabot[bot] | 1bb8e9302c | |
dependabot[bot] | a57512d083 | |
Charlotte Som | c4cf9c156a | |
Cadey Ratio | 60196d90ed | |
Cadey Ratio | 7c7904c17c | |
Cadey Ratio | 7cf1429afa | |
Cadey Ratio | 554dbbb53a | |
Cadey Ratio | 2d00c19205 | |
Cadey Ratio | bdc64f78f2 | |
Cadey Ratio | ff64215d07 | |
Cadey Ratio | a12c957abe | |
Cadey Ratio | 71c33c083a | |
Cadey Ratio | ac12ebf063 | |
Cadey Ratio | ffab774e6a | |
Cadey Ratio | f8e2212549 | |
Cadey Ratio | 356f12cbdc | |
Cadey Ratio | 06b00eb7c3 | |
henri | b1277d209d | |
Shadlock0133 | 901a306002 | |
Cadey Ratio | e545abeb1a | |
dependabot[bot] | 08d96305af | |
Cadey Ratio | 019af1d532 | |
Cadey Ratio | 7c920ca5e9 | |
Cadey Ratio | 8c88f66c67 | |
Cadey Ratio | d4145bd406 | |
dependabot[bot] | e080361dd4 | |
dependabot[bot] | ba49eb8f12 | |
dependabot[bot] | 00d101b393 | |
dependabot[bot] | b53cd41193 | |
dependabot[bot] | 09aba58ebd | |
Cadey Ratio | 230df6f54e | |
Cadey Ratio | 565949cec2 | |
Cadey Ratio | e2b9f384bf | |
Nat Amundsen | 0e22f4c224 | |
Cadey Ratio | 62014b2dba | |
Cadey Ratio | 62dc15c339 | |
Cadey Ratio | 2432b5a4fc | |
Cadey Ratio | 7a3d64fec1 | |
Cadey Ratio | b3bdb9388a | |
Cadey Ratio | c5cbcc47ec | |
Cadey Ratio | c5ff939007 | |
Cadey Ratio | c55ef48ba3 | |
Cadey Ratio | bdc85b1536 | |
Cadey Ratio | b1264c8b69 | |
Cadey Ratio | 1d0066eeda | |
Cadey Ratio | 43a542e192 | |
Cadey Ratio | 7e92f3c7a9 | |
Cadey Ratio | 737b4700a0 | |
Cadey Ratio | 22ab51b29c | |
Cadey Ratio | b312b9931d | |
dependabot[bot] | e057c81325 | |
dependabot[bot] | fd6d806365 | |
dependabot[bot] | e351243126 | |
dependabot[bot] | eee6502aa1 | |
Charlie Groves | c07ac3b6c0 | |
Cadey Ratio | 06d4bf7d69 | |
Cadey Ratio | 261d0b65df | |
Nat Amundsen | 628b572455 | |
Cadey Ratio | 6be7bd7613 | |
Cadey Ratio | cd1ce7785a | |
dependabot[bot] | a257536b58 | |
Cadey Ratio | add0fa3e37 | |
Cadey Ratio | e03e1712b1 | |
Cadey Ratio | dacc7159d7 | |
Cadey Ratio | 021f70fd90 | |
dependabot[bot] | f7aa184c20 | |
dependabot[bot] | 1dfd47708f | |
dependabot[bot] | 4d05bd7347 | |
dependabot[bot] | 22c29ce498 | |
dependabot[bot] | 1019e42fa7 | |
dependabot[bot] | 4170e3b78c | |
Cadey Ratio | ad2f5c739f | |
Cadey Ratio | 05135edcbe | |
Cadey Ratio | 9566b790bc | |
Cadey Ratio | 67de839da8 | |
Cadey Ratio | f590fc71d1 | |
Cadey Ratio | 2e539512b7 | |
Cadey Ratio | f51752ed3c | |
dependabot[bot] | e825b1b904 | |
Cadey Ratio | 20aeb35890 | |
Cadey Ratio | 449ddabce1 | |
Cadey Ratio | 6b771b5503 | |
Cadey Ratio | ea8e1e045a | |
Cadey Ratio | 3a4827c887 | |
Cadey Ratio | fd6ac469a6 | |
Cadey Ratio | fa2ada9747 | |
Cadey Ratio | 3a5c7adc42 | |
Cadey Ratio | e5ee825c0a | |
Cadey Ratio | e665412345 | |
kjain | 828a5f277e | |
Cadey Ratio | 7c90296bf0 | |
Cadey Ratio | 1c8c3396a7 | |
Cadey Ratio | 0c0c5875e6 | |
Cadey Ratio | 7fdae76543 | |
Cadey Ratio | 1bedcb6a25 | |
Martin Schwaighofer | 66574582f2 | |
dependabot[bot] | cb65b7b037 | |
Cadey Ratio | 04b78d997b | |
Cadey Ratio | 0d11a2e674 | |
Cadey Ratio | e370af8bd5 | |
Cadey Ratio | 8f187e325c | |
Cadey Ratio | 7e6090274a | |
Cadey Ratio | 8b747c1c40 | |
Cadey Ratio | f45ca40ae1 | |
Cadey Ratio | 10a086d6f2 | |
Cadey Ratio | e4786467df | |
Cadey Ratio | 1364b30305 | |
Cadey Ratio | 05379c9b4c | |
Cadey Ratio | 8fc69d4978 | |
Cadey Ratio | 9e781d2246 | |
Cadey Ratio | 55c661197e | |
Cadey Ratio | ab36b7739d | |
Cadey Ratio | 92f2472411 | |
Cadey Ratio | 7a0fcf88ec | |
Cadey Ratio | b8e4717a5b | |
Cadey Ratio | 249676f0cc | |
dependabot[bot] | c5c281edbf | |
dependabot[bot] | 6694fbfbec | |
Cadey Ratio | 6404b7ef8f | |
Cadey Ratio | bc17472184 | |
Cadey Ratio | b9b96ab56e | |
Cadey Ratio | be845fe82a | |
Cadey Ratio | ce134052ef | |
Cadey Ratio | 809ffaa5a3 | |
Cadey Ratio | f5e21d0c44 | |
Cadey Ratio | 0db69641a5 | |
Cadey Ratio | b3d341d954 | |
Eliot Partridge | c2099e450f | |
Cadey Ratio | a7534a801e | |
Cadey Ratio | 11d626d265 | |
Cadey Ratio | 061d069f72 | |
dependabot[bot] | b0e2ed1da8 | |
Cadey Ratio | 8e1f4c9c10 | |
Cadey Ratio | f4eac80c73 | |
Cadey Ratio | 997f66f03a | |
Cadey Ratio | f622ae7277 | |
dependabot[bot] | 99f302a44a | |
Cadey Ratio | 97e31d0e8b | |
dependabot[bot] | ce0ab58292 | |
Cadey Ratio | b46138c03d | |
Cadey Ratio | c7b2db9d54 | |
Cadey Ratio | addd70d2ac | |
Cadey Ratio | 23629ade45 | |
dependabot[bot] | a77347063f | |
Cadey Ratio | 37043c8085 | |
dependabot[bot] | bc4420cf19 | |
Cadey Ratio | d951dc438d | |
Cadey Ratio | ee69f652e5 | |
Cadey Ratio | 7c3a00ff11 | |
Eliot Partridge | 0fcaf87b1a | |
Cadey Ratio | 6df97ccc87 | |
Cadey Ratio | b95a8760e4 | |
Cadey Ratio | 66fd857b56 | |
Cadey Ratio | 540ae4a3a9 | |
Cadey Ratio | 934d45057a | |
Cadey Ratio | 15058ffed2 | |
Cadey Ratio | 3d06322011 | |
Cadey Ratio | 166079f0e3 | |
Cadey Ratio | 1986de12d1 | |
Cadey Ratio | 59326804dd | |
Cadey Ratio | a66f15caeb | |
Cadey Ratio | 912fd7473d | |
Cadey Ratio | 3937405b85 | |
Cadey Ratio | 05f56ad3c3 | |
Cadey Ratio | 83d1fb8ad4 | |
sseering | 75995f7fc1 | |
dependabot[bot] | 146e4022cf | |
dependabot[bot] | 1ce8caced0 | |
Cadey Ratio | 12355bf77f | |
Cadey Ratio | 14b65a2e16 | |
Cadey Ratio | 5050da9d88 | |
Cadey Ratio | a7b817d99d | |
Cadey Ratio | 862060458e | |
Cadey Ratio | 19c7175b0a | |
dependabot[bot] | 86b965eb13 | |
Cadey Ratio | 4cdc658dc2 | |
Cadey Ratio | 8ec8ce8b59 | |
Cadey Ratio | 048db0934e | |
Cadey Ratio | 48a569c8ed | |
dependabot[bot] | 65bd9b4c20 | |
Cadey Ratio | 9617d95c12 | |
Cadey Ratio | 8245507a77 | |
Cadey Ratio | d3a0498cc0 | |
Cadey Ratio | f95d4547ba | |
dependabot[bot] | bad76eba8e | |
dependabot[bot] | 900b6332f3 | |
dependabot[bot] | 179e945ef8 | |
dependabot[bot] | bd19beee7e | |
Cadey Ratio | 914174bae1 | |
Cadey Ratio | 0979a248b0 | |
Cadey Ratio | 2c338087b7 | |
Cadey Ratio | edce90cfa4 | |
Cadey Ratio | 9f45d3026c | |
Cadey Ratio | ec3ca6841c | |
Cadey Ratio | 4e0d107228 | |
Cadey Ratio | 92b253972c | |
Cadey Ratio | 7bdd2936c2 | |
artemis | dfe84da074 | |
Cadey Ratio | e668250e16 | |
Cadey Ratio | dc07e6d938 | |
dependabot[bot] | 0c6eb0474c | |
Cadey Ratio | b3118983bc | |
Cadey Ratio | 7043054b1f | |
Asherah Connor | 425de3f865 | |
dependabot[bot] | cd5cf0740e | |
dependabot[bot] | df32d32700 | |
Cadey Ratio | 698d4cb3af | |
Cadey Ratio | 9dde6e89d2 | |
Cadey Ratio | 0f5159a121 | |
dependabot[bot] | bd38ac142d | |
Cadey Ratio | 0faf12cdd3 | |
Cadey Ratio | c33b24da5d | |
Cadey Ratio | d5e7614477 | |
Björn Richter | 82fabbb8c3 | |
Cadey Ratio | 50cf995263 | |
Cadey Ratio | 9e072ea3db | |
Cadey Ratio | bb1e21cfbb | |
Cadey Ratio | 9980827350 | |
Cadey Ratio | a065b43132 | |
Cadey Ratio | 1d48db940b | |
Cadey Ratio | 6b8b70321c | |
Cadey Ratio | 2654dd37e8 | |
dependabot[bot] | 1bff761acb | |
dependabot[bot] | e867f04894 | |
dependabot[bot] | 585268e381 | |
Cadey Ratio | 5f4db2e9c4 | |
Cadey Ratio | d752cd91b1 | |
Cadey Ratio | fbccd757d5 | |
Cadey Ratio | aa6a92c061 | |
Cadey Ratio | b90b9a86db | |
Cadey Ratio | 57e78ef8a5 | |
Cadey Ratio | 79c5238817 | |
Cadey Ratio | a716286f37 | |
Cadey Ratio | 7dfdd131e4 | |
Cadey Ratio | 0019b0a4e9 | |
Cadey Ratio | 8ce69f76c7 | |
Avi Parshan | 3c786a1c1f | |
Cadey Ratio | dae24e0f8e | |
Cadey Ratio | f6c279f2bb | |
dependabot[bot] | 8c71e2e9fb | |
dependabot[bot] | 8e39b0ef54 |
|
@ -6,3 +6,5 @@ cw.tar
|
|||
/result
|
||||
.#*
|
||||
/target
|
||||
.patreon.json
|
||||
.direnv
|
||||
|
|
File diff suppressed because it is too large
Load Diff
41
Cargo.toml
41
Cargo.toml
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "xesite"
|
||||
version = "2.3.0"
|
||||
authors = ["Christine Dodrill <me@christine.website>"]
|
||||
version = "2.4.0"
|
||||
authors = ["Xe Iaso <me@christine.website>"]
|
||||
edition = "2018"
|
||||
build = "src/build.rs"
|
||||
repository = "https://github.com/Xe/site"
|
||||
|
@ -9,21 +9,32 @@ repository = "https://github.com/Xe/site"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
color-eyre = "0.5"
|
||||
axum = { version = "0.5", features = ["headers"] }
|
||||
axum-macros = "0.2"
|
||||
axum-extra = "0.3"
|
||||
color-eyre = "0.6"
|
||||
chrono = "0.4"
|
||||
comrak = "0.10"
|
||||
comrak = "0.14.0"
|
||||
derive_more = "0.99"
|
||||
dirs = "4"
|
||||
envy = "0.4"
|
||||
estimated_read_time = "1"
|
||||
futures = "0.3"
|
||||
glob = "0.3"
|
||||
http = "0.2"
|
||||
http-body = "0.4"
|
||||
hyper = "0.14"
|
||||
kankyo = "0.3"
|
||||
lazy_static = "1.4"
|
||||
log = "0.4"
|
||||
lol_html = "0.3"
|
||||
maud = { version = "0.23.0", features = ["axum"] }
|
||||
mime = "0.3.0"
|
||||
prometheus = { version = "0.12", default-features = false, features = ["process"] }
|
||||
prometheus = { version = "0.13", default-features = false, features = ["process"] }
|
||||
rand = "0"
|
||||
regex = "1"
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
serde_dhall = "0.10.1"
|
||||
serde_dhall = "0.11.2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_yaml = "0.8"
|
||||
sitemap = "0.4"
|
||||
|
@ -32,25 +43,33 @@ tokio = { version = "1", features = ["full"] }
|
|||
tokio-stream = { version = "0.1", features = ["net"] }
|
||||
tracing = "0.1"
|
||||
tracing-futures = "0.2"
|
||||
tracing-subscriber = { version = "0.2", features = ["fmt"] }
|
||||
warp = "0.3"
|
||||
tracing-subscriber = { version = "0.3", features = ["fmt"] }
|
||||
xml-rs = "0.8"
|
||||
url = "2"
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
|
||||
xesite_types = { path = "./lib/xesite_types" }
|
||||
|
||||
# workspace dependencies
|
||||
cfcache = { path = "./lib/cfcache" }
|
||||
go_vanity = { path = "./lib/go_vanity" }
|
||||
jsonfeed = { path = "./lib/jsonfeed" }
|
||||
xe_jsonfeed = { path = "./lib/jsonfeed" }
|
||||
mi = { path = "./lib/mi" }
|
||||
patreon = { path = "./lib/patreon" }
|
||||
|
||||
[dependencies.tower]
|
||||
version = "0.4"
|
||||
features = [ "full" ]
|
||||
|
||||
[dependencies.tower-http]
|
||||
version = "0.3"
|
||||
features = [ "full" ]
|
||||
|
||||
# os-specific dependencies
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
sdnotify = { version = "0.2", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
ructe = { version = "0.13", features = ["warp02"] }
|
||||
ructe = { version = "0.14", features = [ "mime03" ] }
|
||||
|
||||
[dev-dependencies]
|
||||
pfacts = "0"
|
||||
|
|
25
README.md
25
README.md
|
@ -6,3 +6,28 @@ nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org)
|
|||
![Rust](https://github.com/Xe/site/workflows/Rust/badge.svg)
|
||||
|
||||
My personal/portfolio website.
|
||||
|
||||
## <big>Information for people wishing to use this code</big>
|
||||
|
||||
Don't. This code is not made for you to be able to use without extensive
|
||||
modification. The [license](https://github.com/Xe/site/blob/main/LICENSE) of
|
||||
this code is intentionally chosen in such a way that it will make reuse of this
|
||||
website code verbatim very difficult.
|
||||
|
||||
If you are still adamant about using this backend, please keep several things in
|
||||
mind:
|
||||
|
||||
1. All blog content is all rights reserved. I aggressively pursue and report
|
||||
content theft.
|
||||
2. You _must_ fully comply with the license. I will aggressively pursue people
|
||||
that are not in compliance with the license.
|
||||
3. You are on your own. I will not help you. This is code I made for myself and
|
||||
it's only really open source as a side effect of making deployment on NixOS
|
||||
easier. Please do not be the person that makes me have to take this repo
|
||||
closed source.
|
||||
4. Upon security issues being found and remediated, you will not be notified
|
||||
about issues or remediation instructions.
|
||||
|
||||
This is probably not what you are looking for. Make your own website. Look into
|
||||
[Hugo](http://gohugo.io/) or [Zola](https://www.getzola.org/). They are going to
|
||||
be better maintained than this site will be.
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
title: Compiling Code to Matter in My Living Room
|
||||
date: 2022-03-28
|
||||
tags:
|
||||
- openscad
|
||||
- 3dprinting
|
||||
---
|
||||
|
||||
In a moment of weakness, my husband and I got a 3d printer. It's mostly been sitting around and not doing much since we got it, but recently I found a great use for it: I wanted a controller stand for my Valve Index controllers and VR full body trackers.
|
||||
|
||||
After doing some digging on Thingiverse, I found [this stand](https://www.thingiverse.com/thing:4587097) that looked like it had promise. So I downloaded the model, sliced it and then sent it over to Kyubey:
|
||||
|
||||
<blockquote class="twitter-tweet"><p lang="tl" dir="ltr">Kyuubey is happy <a href="https://t.co/atTLN8MSgc">pic.twitter.com/atTLN8MSgc</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1507485129907871747?ref_src=twsrc%5Etfw">March 25, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
[Kyubey's name is a reference to <a href="https://madoka.fandom.com/wiki/Kyubey">Kyubey</a> from Puella Magi Madoka Magika</a>.](conversation://Mara/hacker)
|
||||
|
||||
Once it was done I ended up with a stand that I could feed [these cables I got from Amazon](https://www.amazon.ca/gp/product/B09LSF8XL9/) through. The tracker holes worked great, but the controller holes were just barely too small.
|
||||
|
||||
This was kinda frustrating and I almost gave up on the project, but then I remembered that [OpenSCAD](https://openscad.org) existed. OpenSCAD is a weird programming environment / 3D modeling hybrid program that I've seen used on Thingiverse. It works by letting you position platonic solids into a 3d environment, and from there you can create anything you want.
|
||||
|
||||
One of the primitives that OpenSCAD offers is a cylinder. So I wondered if I could use one of those to widen the hole in the index stand and then reprint the part with the wider hole.
|
||||
|
||||
[Wait, you're using a CAD program to fix your 3D print by modifying the model instead of using, I don't know, a drill and 5 minutes to make it fit that way?](conversation://Numa/dismay)
|
||||
|
||||
[There's no doing like overdoing!](conversation://Cadey/enby)
|
||||
|
||||
After some finangling, I managed to get the cylinders in the right place with this OpenSCAD code:
|
||||
|
||||
```scad
|
||||
//difference() {
|
||||
color("magenta") translate([0, 0, 0]) import("./assets/ValveTrackerDeckEditedByInugoro.stl");
|
||||
// bores for controller holders
|
||||
color([0, 1, 0]) translate([63, 44, 0]) cylinder(h = 55, r = 4.75);
|
||||
color([0, 1, 0]) translate([-63, 44, 0]) cylinder(h = 55, r = 4.75);
|
||||
//}
|
||||
```
|
||||
|
||||
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Some finagling required <a href="https://t.co/7T0R6x1XoP">pic.twitter.com/7T0R6x1XoP</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1508566854926745614?ref_src=twsrc%5Etfw">March 28, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
And when I uncommented out the `difference()` block, it ends up looking good enough:
|
||||
|
||||
<blockquote class="twitter-tweet" data-conversation="none" data-dnt="true"><p lang="und" dir="ltr"><a href="https://t.co/fiShvlN8QH">pic.twitter.com/fiShvlN8QH</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1508567556759728141?ref_src=twsrc%5Etfw">March 28, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
So then I took a good solid look at the rest of the 3D printed part to see if I could improve on anything else before I sent it to another round of the printer. The last stand took _14 hours_ to print and used a lot of material. I want to avoid waste.
|
||||
|
||||
Something I noticed is that the front of the print where all the cables come out was a bit too thin. All 5 of the cables wouldn't fit in there (my braided cables must have been thicker than the ones that the original modeler used). So again I grabbed a few platonic solids and managed to make it work out:
|
||||
|
||||
```scad
|
||||
// widen the paths
|
||||
color("green") translate([0, -16, 1.3]) rotate([0, 0, 90]) cube([10, 57, 7.8], center = true);
|
||||
color("green") translate([0, 0, 1.7]) rotate([0, 0, 0]) cube([25, 30, 7], center = true);
|
||||
```
|
||||
|
||||
<blockquote class="twitter-tweet" data-conversation="none" data-dnt="true"><p lang="und" dir="ltr"><a href="https://t.co/pKAVtiPfDS">pic.twitter.com/pKAVtiPfDS</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1508568858650685440?ref_src=twsrc%5Etfw">March 28, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
Then I wanted to add some wedges into the underside of the part to help me get the print off the bed. Most people have a problem with bed adhesion being too little. I have too much bed adhesion. So I added some angled rectangles:
|
||||
|
||||
```scad
|
||||
// wedges to help get the print off the bed
|
||||
color([1, 1, 0]) translate([-120, 0, 0]) rotate([15, 0, 90]) cube([10, 11, 2], center = true); // right
|
||||
color([1, 1, 0]) translate([120, 0, 0]) rotate([-15, 0, 90]) cube([10, 11, 2], center = true); // left
|
||||
color([1, 1, 0]) translate([0, -85, 0]) rotate([0, 15, 90]) cube([10, 11, 2], center = true); // back
|
||||
color([1, 1, 0]) translate([60, 56, 1]) rotate([0, -15, 90]) cube([10, 11, 2], center = true); // front left
|
||||
color([1, 1, 0]) translate([-60, 56, 1]) rotate([0, -15, 90]) cube([10, 11, 2], center = true); // front right
|
||||
color([1, 1, 0]) translate([32.5, 41, 1]) rotate([0, -15, 130]) cube([10, 11, 2], center = true); // front left inner
|
||||
color([1, 1, 0]) translate([-32.5, 41, 1]) rotate([0, -15, 60]) cube([10, 11, 2], center = true); // front right inner
|
||||
```
|
||||
|
||||
<blockquote class="twitter-tweet" data-conversation="none" data-dnt="true"><p lang="und" dir="ltr"><a href="https://t.co/XUQ9ZeYk1H">pic.twitter.com/XUQ9ZeYk1H</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1508569796253827077?ref_src=twsrc%5Etfw">March 28, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
And then once I spun it around for a bit and thought it was good, I sliced it in PrusaSlicer and sent it off to Kyubey. It was going to take 14 hours, so I went off to do other things, ate dinner and then went to bed while the printer continued.
|
||||
|
||||
<blockquote class="twitter-tweet" data-conversation="none" data-dnt="true"><p lang="fr" dir="ltr">Diligent bean <a href="https://t.co/yPgnJA0ZdW">pic.twitter.com/yPgnJA0ZdW</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1508397506031460352?ref_src=twsrc%5Etfw">March 28, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
Then when I woke up, Kyubey was done:
|
||||
|
||||
<blockquote class="twitter-tweet" data-conversation="none" data-dnt="true"><p lang="und" dir="ltr"><a href="https://t.co/2E1IS810EH">pic.twitter.com/2E1IS810EH</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1508407046995156992?ref_src=twsrc%5Etfw">March 28, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
I was excited and chiseled the print off the bed (the wedges helped a little, but it ended up making the print look kinda weird so I don't know if I will do that again), but the hole for the middle tracker didn't fit perfectly. Everything else did though.
|
||||
|
||||
[If you want to get prints off your printer easier, see this video for the method we're starting to use: <br /><br /><iframe width="560" height="315" src="https://www.youtube.com/embed/VCCbzCvtRzU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>](conversation://Mara/hacker)
|
||||
|
||||
I looked on my desk and found that a random pen that I had sitting around for months was about the right size, so I pushed it into and out of the hole a few times and then the cables fit perfectly. I assume some plastic was in a weird state or something.
|
||||
|
||||
Then I set everything up and I had my Index controller stand:
|
||||
|
||||
<blockquote class="twitter-tweet" data-conversation="none" data-dnt="true"><p lang="en" dir="ltr">Victory! <a href="https://t.co/A3aCtQMQt5">pic.twitter.com/A3aCtQMQt5</a></p>— Xe Iaso (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1508426229464064001?ref_src=twsrc%5Etfw">March 28, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
[I really need to get a table or something for this.](conversation://Cadey/facepalm)
|
||||
|
||||
I've uploaded my modified version to [Thingiverse](https://www.thingiverse.com/thing:5332988). If you want to see the OpenSCAD code, you can check it out on GitHub [here](https://github.com/Xe/3dstuff/blob/main/index_stand_hack.scad). I'm really liking OpenSCAD so far. It's very weird but it lets you do whatever you want by chaining together basic shapes to build up to what you want. I imagine I will be using it a lot in the future, especially once my husband's new sim racing gear comes in.
|
||||
|
||||
Having a 3D printer around is like having a very weird superpower on standby. You can compile matter in your living room, but you need a very pedantic description of what that should look like. You also can have any material you like as long as it's plastic. However when it's useful, it's a lifesaver. You can make something to fit a gap or mend something broken or even add functionality to something that lacked it. The cloud's the limit!
|
|
@ -5,8 +5,6 @@ tags:
|
|||
- ttrpg
|
||||
---
|
||||
|
||||
# The 7th Edition
|
||||
|
||||
You know what, fuck rules. Fuck systems. Fuck limitations. Let's dial the
|
||||
tabletop RPG system down to its roots. Let's throw out every stat but one:
|
||||
Awesomeness. When you try to do something that could fail, roll for Awesomeness.
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- release
|
||||
---
|
||||
|
||||
# OVE-20190623-0001
|
||||
|
||||
## Within Security Advisory
|
||||
|
||||
Root-level Remote Command Injection in the [V](https://vlang.io) playground (OVE-20190623-0001)
|
||||
|
|
|
@ -9,8 +9,6 @@ tags:
|
|||
- oh-dear-god
|
||||
---
|
||||
|
||||
# OVE-20191021-0001
|
||||
|
||||
## Within Security Advisory
|
||||
|
||||
Multiple vulnerabilities in the mysqljs API and code.
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- golang
|
||||
---
|
||||
|
||||
# TL;DR Rust
|
||||
|
||||
Recently I've been starting to use Rust more and more for larger and larger
|
||||
projects. As things have come up, I realized that I am missing a good reference
|
||||
for common things in Rust as compared to Go. This post contains a quick
|
||||
|
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- offmychest
|
||||
---
|
||||
|
||||
# A Letter to Those Who Bullied Me
|
||||
|
||||
Hey,
|
||||
|
||||
I'm not angry at you. I don't want to propagate hate. In a way, I almost feel like I should be thanking you for the contributions you've made in making me into the person I am today. Without you all, I would have had a completely different outcome in life. I would have stayed in the closet for good like I had planned. I would have probably ended up boring. I would have never met my closest friends and some even more.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
title: "Site Update: A Sigil"
|
||||
date: 2022-01-11
|
||||
---
|
||||
|
||||
<style>
|
||||
.logo-wumbo {
|
||||
background-color: #fdf5d7;
|
||||
-webkit-mask: url("/static/img/xeiaso.svg");
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100%;
|
||||
mask: url("/static/img/xeiaso.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: 100%;
|
||||
width: 9.5em;
|
||||
height: 16em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
.logo-wumbo {
|
||||
background-color: #1d2021;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
The upper left-hand corner of my website has gotten more interesting as of
|
||||
recently. I have decided to experiment with adding an SVG icon to the upper left
|
||||
hand corner of the page.
|
||||
|
||||
This is the sigilized form of the name `Xe Iaso`. This sigil is equivalent in
|
||||
meaning and semantics to the name `Xe Iaso`. Here is a version of it in a much
|
||||
bigger size:
|
||||
|
||||
<center><span class="logo-wumbo"></span></center>
|
||||
|
||||
[Fun fact: the sigil is written using <a
|
||||
href="https://greggshorthand.github.io/index.html">Gregg Shorthand</a>. It says
|
||||
the phonetic equivalent of `Xe Iaso`.](conversation://Mara/hacker)
|
||||
|
||||
I have tested this in Edge on Linux, Firefox on Linux, Chrome on Android and
|
||||
Safari on iOS. This should cover most of the big web browsers, but surely I've
|
||||
missed something. If you use a _modern release_ of a _standards compliant_ web
|
||||
browser and you don't see a logo anywhere on the page, please let me know so I
|
||||
can go cry and then hopefully fix the issue.
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: A Tool to Aid Forgetfulness
|
||||
date: 2022-01-12
|
||||
series: stories
|
||||
---
|
||||
|
||||
The Egyptian God Thoth lived in the Egyptian city of Naucratis. Thoth was the
|
||||
inventor of many arts such as math and astronomy, but the most significant was
|
||||
the invention of writing. Thoth showed writing to the king of Egypt, claiming
|
||||
that it would make Egyptians wiser and give them better memories; that it it
|
||||
would vastly improve both the memory and the wit of the Egyptian people.
|
||||
|
||||
The king replied: "Thoth, you invented this tool. As such you are not the best
|
||||
one to judge such things. You have not created a tool to aid memory, you have
|
||||
created a tool to aid forgetfulness. Learners will not use their memories, they
|
||||
will blindly trust these sigils and not remember for themselves.
|
||||
|
||||
"You have discovered an aid to vague recollection, as the users of this tool
|
||||
will not be given truth. They will only be given a semblance of truth.
|
||||
|
||||
"They will be hearers of many things and learners of nothing. They will appear
|
||||
to know all the knowledge of the world yet when asked they will only be the
|
||||
middleman to external forces that are trusted without verification. They will
|
||||
know wisdom, but not truth."
|
||||
|
||||
Adapted from The Dialogues of Plato in Five Volumes, 3rd ed. Oxford
|
||||
University, 1892. Vol. 1 pp. 483-489.
|
|
@ -5,8 +5,6 @@ tags:
|
|||
- freebsd
|
||||
---
|
||||
|
||||
# A Trip into FreeBSD
|
||||
|
||||
I normally deal with Linux machines. Linux is what I know and it's what I've
|
||||
been using since I was in college. A friend of mine has been coaxing me into
|
||||
trying out [FreeBSD](https://www.freebsd.org), and I decided to try it out and
|
||||
|
|
|
@ -6,10 +6,8 @@ tags:
|
|||
- o11y
|
||||
---
|
||||
|
||||
# Prometheus and Aegis
|
||||
|
||||
[*Last time in the christine dot website cinematic
|
||||
universe:*](https://christine.website/blog/unix-domain-sockets-2021-04-01)
|
||||
universe:*](https://xeiaso.net/blog/unix-domain-sockets-2021-04-01)
|
||||
|
||||
*Unix sockets started to be used to grace the cluster. Things were at peace.
|
||||
Then, a realization came through:*
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
title: "My Stance on Toxicity About Programming Languages"
|
||||
date: 2022-05-23
|
||||
tags:
|
||||
- toxicity
|
||||
- culture
|
||||
---
|
||||
|
||||
I have been toxic and hateful in the past about programming language choice. I
|
||||
now realize this is a mistake. I am sorry if my being toxic about programming
|
||||
languages has harmed you.
|
||||
|
||||
By toxic, I mean doing things or saying things that imply people are lesser for
|
||||
having different experience and preferences about programming languages. I have
|
||||
seen people imply that using languages like PHP or Node.js means that they are
|
||||
idiots or similar. This is toxic behavior and I do not want to be a part of it
|
||||
in the future.
|
||||
|
||||
I am trying to not be toxic about programming languages in the future. Each
|
||||
programming language is made to solve the tasks it was designed to solve and
|
||||
being toxic about it helps nobody. By being toxic about programming languages
|
||||
like this, I only serve to spread toxicity and then see it be repeated as the
|
||||
people that look up to me as a role model will then strive to repeat my
|
||||
behavior. This cannot continue. I do not want my passion projects to become
|
||||
synonymous with toxicity and vitriol. I do not want to be known as the person
|
||||
that hates $PROGRAMMING_LANGUAGE. I want to break the cycle.
|
||||
|
||||
With this, I want to confirm that I will not write any more attack articles
|
||||
about programming languages. I am doing my best to ensure that this will also
|
||||
spread to my social media actions, conference talks and as many other things as
|
||||
I can.
|
||||
|
||||
I challenge all of you readers to take this challenge too. Don't spread toxicity
|
||||
about programming languages. All of the PHP hate out there is a classic example
|
||||
of this. PHP is a viable programming language that is used by a large percentage
|
||||
of the internet. By insinuating that everyone using PHP is inferior (or worse)
|
||||
you only serve to push people away and worst case cause them to be toxic about
|
||||
the things you like. Toxicity breeds toxicity and the best way to stop it is to
|
||||
be the one to break the cycle and have others follow in your footsteps.
|
||||
|
||||
I have been incredibly toxic about PHP in the past. PHP is one of if not the
|
||||
most widely used programming languages for writing applications that run on a
|
||||
web server. Its design makes it dead simple to understand how incoming HTTP
|
||||
requests relate to files on the disk. There is no compile step. The steps to
|
||||
make a change are to open the file on the server, make the change you want to
|
||||
see and press F5. This is a developer experience that is unparalleled in most
|
||||
HTTP frameworks that I've seen in other programming environments. PHP users
|
||||
deserve better than to be hated on. PHP is an incredibly valid choice and I'm
|
||||
sure that with the right linters and human review in the mix it can be as secure
|
||||
as "properly written" services in Go, Java and Rust.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="enby">Take the "don't be toxic about programming
|
||||
languages" challenge! Just stop with the hate, toxicity and vitriol. Our jobs
|
||||
are complicated enough already. Being toxic to eachother about how we decide to
|
||||
solve problems is a horrible life decision at the least and actively harmful to
|
||||
people's careers at most. Just stop.</xeblog-conv>
|
||||
|
||||
---
|
||||
|
||||
<xeblog-conv name="Mara" mood="hacker">This post is not intended as a sub-blog.
|
||||
If you feel that this post is calling you out, please don't take this
|
||||
personally. There is a lot of toxicity out there and it will take a long time to
|
||||
totally disarm it, even with people dedicated to doing it. This is an adaptation
|
||||
of [this twitter
|
||||
thread](https://twitter.com/theprincessxena/status/1527765025561186304).</xeblog-conv>
|
|
@ -4,8 +4,6 @@ date: 2019-05-25
|
|||
series: dreams
|
||||
---
|
||||
|
||||
# All There is is Now
|
||||
|
||||
The dream scenario was going on for a while uneventfully. I saw an old man walking around and ranting about things. I decided to go and talk with him.
|
||||
|
||||
"You fools! Time doesn't exist! The past is immutable! Don't worry about your trivial daily needs. All there is is Now!"
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- makes-u-thonk
|
||||
---
|
||||
|
||||
# Outsider Art and Anathema
|
||||
|
||||
This was going to be a post about [Urbit][urbit] at first; but in the process of discussing about my interest in writing something _positive_ about it, I was warned by a few people that this was a Bad Idea. I was focusing purely on the technical side of it and how closely it implemented a concept called [liquid software][liquidsoftware], but from what people were saying, it seemed like a creation that was spoiled by something outside of it, specifically the creator's political views (of which I had little idea at the time).
|
||||
|
||||
As much as I will probably return to the original concept in the future with another post, this feels like something I had to address first.
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
---
|
||||
title: "Anbernic Win600 First Impressions"
|
||||
date: 2022-07-14
|
||||
series: reviews
|
||||
---
|
||||
|
||||
Right now PC gaming is largely a monopoly centered around Microsoft Windows.
|
||||
Many PC games only support Windows and a large fraction of them use technical
|
||||
means to prevent gamers on other platforms from playing those games. In 2021,
|
||||
Valve introduced the [Steam Deck](https://www.steamdeck.com/en/) as an
|
||||
alternative to that monopoly. There's always been a small, underground market
|
||||
for handheld gaming PCs that let you play PC games on the go, but it's always
|
||||
been a very niche market dominated by a few big players that charge a lot of
|
||||
money relative to the game experience they deliver. The Steam Deck radically
|
||||
changed this equation and it's still on backorder to this day. This has made
|
||||
other manufacturers take notice and one of them was Anbernic.
|
||||
|
||||
[Anbernic](https://anbernic.com/) is a company that specializes in making retro
|
||||
emulation handheld gaming consoles. Recently they released their
|
||||
[Win600](https://anbernic.com/products/new-anbernic-win600) handheld. It has a
|
||||
Radeon Silver 3020e or a Radeon Silver 3050e and today I am going to give you my
|
||||
first impressions of it. I have the 3050e version.
|
||||
|
||||
<xeblog-conv name="Mara" mood="happy">A review of the Steam Deck is coming up
|
||||
soon!</xeblog-conv>
|
||||
|
||||
One of the real standout features of this device is that Anbernic has been
|
||||
working with Valve to allow people to run SteamOS on it! This makes us all one
|
||||
step closer to having a viable competitor to Windows for gaming. SteamOS is
|
||||
fantastic and has revolutionized gaming on Linux. It's good to see it coming to
|
||||
more devices.
|
||||
|
||||
## Out of the box
|
||||
|
||||
I ordered my Win600 about 3 hours after sales opened. It arrived in a week and
|
||||
came in one of those china-spec packages made out of insulation. If you've ever
|
||||
ordered things from AliExpress you know what I'm talking about. It's just a
|
||||
solid mass of insulation.
|
||||
|
||||
[![The console siting on my desk with its charging brick and included cable](https://cdn.xeiaso.net/file/christine-static/img/FXozAEjUsAQEg9d-smol.jpeg)](https://cdn.xeiaso.net/file/christine-static/img/FXozAEjUsAQEg9d.jpeg)
|
||||
|
||||
The unboxing experience was pretty great. The console came with:
|
||||
|
||||
* The console
|
||||
* A box containing the charger and cable
|
||||
* A slip of paper telling you how to set up windows without a wifi connection
|
||||
* A screen protector and cleaning cloth (my screen protector was broken in the
|
||||
box, so much for all that insulation lol)
|
||||
* A user manual that points out obvious things about your device
|
||||
|
||||
One of the weirder things about this device is the mouse/gamepad slider on the
|
||||
side. It changes the USB devices on the system and makes the gamepad either act
|
||||
like an xinput joypad or a mouse and keyboard. The mouse and keyboard controls
|
||||
are strange. Here are the controls I have discovered so far:
|
||||
|
||||
* R1 is right click
|
||||
* L1 is left click
|
||||
* A is enter
|
||||
* The right stick very slowly skitters the mouse around the screen
|
||||
* The left stick is a super aggressive scroll wheel
|
||||
|
||||
Figuring out these controls on the fly without any help from the manual meant
|
||||
that I had taken long enough in the setup screen that [Cortana started to pipe
|
||||
up](https://youtu.be/yn6bSm9HXFg) and guided me through the setup process. This
|
||||
was not fun. I had to connect an external keyboard to finish setup.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="coffee">This is probably not Anbernic's fault.
|
||||
Windows is NOT made for smaller devices like this and oh god it
|
||||
shows.</xeblog-conv>
|
||||
|
||||
## Windows 10 "fun"
|
||||
|
||||
There is also a keyboard button on the side. When you are using windows this
|
||||
button summons a soft keyboard. Not the nice to use modern soft keyboard though,
|
||||
the legacy terrible soft keyboard that Microsoft has had for forever and never
|
||||
really updated. Using it is grating, like rubbing sandpaper all over your hands.
|
||||
This made entering in my Wi-Fi password an adventure. It took my husband and I
|
||||
15 minutes to get the device to connect to Wi-Fi. 15 minutes to connect to
|
||||
Wi-Fi.
|
||||
|
||||
Once it was connected to Wi-Fi, I tried to update the system to the latest
|
||||
version of windows. The settings update crashed. Windows Update's service also
|
||||
crashed. Windows Update also randomly got stuck trying to start the installation
|
||||
process for updates. Once updates worked and finished installing, I rebooted.
|
||||
|
||||
I tried to clean up the taskbar by disabling all of the random icons that
|
||||
product managers at Microsoft want you to see. The Cortana button was stuck on
|
||||
and I was unable to disable it. Trying to hide the Windows meet icon crashed
|
||||
explorer.exe. I don't know what part of this is Windows going out of its way to
|
||||
mess with me (I'm cursed) and what part of it is Windows really not being
|
||||
optimized for this hardware in any sense of the way.
|
||||
|
||||
Windows is really painful on this device. It's obvious that Windows was not made
|
||||
with this device in mind. There are buttons to hack around this (but not as far
|
||||
as the task manager button I've seen on other handhelds), but overall trying to
|
||||
use Windows with a game console is like trying to saw a log with a pencil
|
||||
sharpener. It's just the wrong tool for the job. Sure you _can_ do it, but _can_
|
||||
and _should_ are different words in English.
|
||||
|
||||
Another weird thing about Windows on this device is that the screen only reports
|
||||
a single display mode: 1280x720. It has no support for lower resolutions to run
|
||||
older games that only work on those lower resolutions. In most cases this will
|
||||
be not an issue, but if you want to lower the resolution of a game to squeeze
|
||||
more performance out then you may have issues.
|
||||
|
||||
## Steam
|
||||
|
||||
In a moment of weakness, I decided to start up Steam. Steam defaulted to Big
|
||||
Picture mode and its first-time-user-experience made me set up Wi-Fi again.
|
||||
There was no way to bypass it. I got out my moonlander again and typed in my
|
||||
Wi-Fi password again, and then I downloaded Sonic Adventure 2 as a test for how
|
||||
games feel on it. Sonic Adventure 2 is a very lightweight game (you can play it
|
||||
for like 6.5 hours on a full charge of the Steam Deck) and I've played it to
|
||||
_death_ over the years. I know how the game _should_ feel.
|
||||
|
||||
[![The starting screen of City Escape in Sonic Adventure 2, with the console propped up with a Steam Controller](https://cdn.xeiaso.net/file/christine-static/img/FXpIjhwUIAUEujg-smol.jpeg)](https://cdn.xeiaso.net/file/christine-static/img/FXpIjhwUIAUEujg.jpeg)
|
||||
|
||||
City Escape ran at a perfect 60 FPS at the device's native resolution. The main
|
||||
thing I noticed though was the position of the analog sticks. Based on the
|
||||
design of the device, I'm pretty sure they were going for something with a
|
||||
PlayStation DualShock 4 layout with the action buttons on the top and the sticks
|
||||
on the bottom. The sticks are too far down on the device. Playing Sonic
|
||||
Adventure 2 was kind of painful.
|
||||
|
||||
## SteamOS
|
||||
|
||||
So I installed SteamOS on the device. Besides a weird issue with 5 GHZ Wi-Fi not
|
||||
working and updates requiring me to reboot the device IMMEDIATELY after
|
||||
connecting to Wi-Fi, it works great. I can install games and they run. The DPI
|
||||
for SteamOS is quite wrong though. All the UI elements are painfully small. For
|
||||
comparison, I put my Steam Deck on the same screen as I had on the Win600. The
|
||||
Steam Deck is on top and the Win600 is on the bottom.
|
||||
|
||||
[![The game overview for Sonic Adventure 2 on both the Steam Deck and Anbernic Win600](https://f001.backblazeb2.com/file/christine-static/img/FXqSz_tVsAAU0wf-smol.jpeg)](https://f001.backblazeb2.com/file/christine-static/img/FXqSz_tVsAAU0wf.jpeg)
|
||||
|
||||
Yeah. It leaves things to be desired.
|
||||
|
||||
When I had SteamOS set up, I did find something that makes the Win600 slightly
|
||||
better than the Steam Deck. When you are adding games to Steam with Emulation
|
||||
Station you need to close the Steam client to edit the leveldb files that Steam
|
||||
uses to track what games you can launch. On the Steam Deck, the Steam client
|
||||
also enables the built-in controllers to act as a keyboard and mouse. This means
|
||||
that you need to poke around and pray with the touchscreen to get EmuDeck games
|
||||
up and running. The mouse/controller switch on the Win600 makes this slightly
|
||||
more convenient because the controllers can always poorly act as a mouse and
|
||||
keyboard.
|
||||
|
||||
When you are in KDE on the Win600, you don't get a soft keyboard at all. This is
|
||||
mildly inconvenient, but can be fixed with the moonlander yet again. Here's a
|
||||
screenshot of what my KDE desktop on the Win600 looks like:
|
||||
|
||||
[![My SteamOS desktop on the Win600, showing Crossette from Xenoblade Chronicles 2 center frame](https://f001.backblazeb2.com/file/christine-static/img/Screenshot_20220714_144655-smol.jpg)](https://f001.backblazeb2.com/file/christine-static/img/Screenshot_20220714_144655.png)
|
||||
|
||||
Overall, SteamOS is a lot more ergonomic in my opinion and will let you play
|
||||
games to your heart's content.
|
||||
|
||||
The D-pad feels really good. I love how it responds. When I did a little bit of
|
||||
Sonic Mania I never felt like I was inaccurate. There were some weird audio
|
||||
hitches on Sonic Mania though where the music would cut out randomly. Not sure
|
||||
what's going on with that. I could play through entire Pokemon games with that
|
||||
D-pad.
|
||||
|
||||
## Conclusions for now
|
||||
|
||||
Overall I'm getting the feeling that this device is _okay_. It's not great, it's
|
||||
not terrible, but it's okay. I need to get some more experience with it, but so
|
||||
far it seems that this device really does have a weight class and oh god if you
|
||||
play a game outside its weight class your UX goes to shit instantly. The battery
|
||||
life leaves _a lot_ to be desired so far. However it does work. It's hard to not
|
||||
compare this to the Steam Deck, but it's so much less in comparison to the Steam
|
||||
Deck.
|
||||
|
||||
I don't know how I feel about this device. I'm not sure it's worth the money. I
|
||||
need to get more experience with it. I'll have a better sense of all this when I
|
||||
write my full review. Stay tuned for that!
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
date: 2021-07-04
|
||||
date: 2021-07-03
|
||||
title: My Thoughts About Using Android Again as an iPhone User
|
||||
tags:
|
||||
- android
|
||||
|
@ -7,8 +7,6 @@ tags:
|
|||
author: ectamorphic
|
||||
---
|
||||
|
||||
# My Thoughts About Using Android Again as an iPhone User
|
||||
|
||||
I used to be a hardcore Android user. It was my second major kind of smartphone
|
||||
(the first was Windows Mobile 6.1 on a T-Mobile Dash) and it left me hooked to
|
||||
the concept of smartphones and connected tech in general. I've used many Android
|
|
@ -6,7 +6,5 @@ tags:
|
|||
redirect_to: https://www.getrevue.co/profile/theprincessxena/issues/animal-crossing-new-horizons-an-island-of-stability-in-an-unstable-world-313933
|
||||
---
|
||||
|
||||
# Animal Crossing New Horizons: An Island of Stability in an Unstable World
|
||||
|
||||
Check out this post [on my
|
||||
newsletter](https://www.getrevue.co/profile/theprincessxena/issues/animal-crossing-new-horizons-an-island-of-stability-in-an-unstable-world-313933)!
|
||||
|
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- aarch64
|
||||
---
|
||||
|
||||
# The Worst Experience I've Had With an aarch64 MacBook
|
||||
|
||||
I've had my hands on this M1 MacBook Air for a few weeks now and I have gotten a
|
||||
lot of opinions about it. I wanted to go over them and give my thoughts. This is
|
||||
an amazing laptop. Its battery life is iPad tier. I can run iPad and iPhone apps
|
||||
|
@ -23,7 +21,7 @@ up being the _worst_ experience that I have using an aarch64 MacBook.
|
|||
[This website](https://github.com/Xe/site) is a fairly complicated webapp
|
||||
written in Rust. As such it makes for a fairly decent compile stress test. I'm
|
||||
going to do a compile test against my [Ryzen
|
||||
3600](https://christine.website/blog/nixos-desktop-flow-2020-04-25) with this M1
|
||||
3600](https://xeiaso.net/blog/nixos-desktop-flow-2020-04-25) with this M1
|
||||
MacBook Air.
|
||||
|
||||
My tower is running this version of Rust:
|
||||
|
|
|
@ -7,9 +7,6 @@ tags:
|
|||
- vim
|
||||
---
|
||||
|
||||
My Experience with Atom as A Vim User
|
||||
=====================================
|
||||
|
||||
Historically, I am a Vim user. People know me as a very very heavy vim
|
||||
user. I have spent almost the last two years customizing [my .vimrc
|
||||
file](https://github.com/Xe/dotfiles/blob/master/.vimrc) and I have parts
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
---
|
||||
title: "</kubernetes>"
|
||||
title: "Goodbye Kubernetes"
|
||||
date: 2021-01-03
|
||||
---
|
||||
|
||||
# </kubernetes>
|
||||
|
||||
Well, since I posted [that last post](/blog/k8s-pondering-2020-12-31) I have had
|
||||
an adventure. A good friend pointed out a server host that I had missed when I
|
||||
was looking for other places to use, and now I have migrated my blog to this new
|
||||
|
@ -183,7 +181,7 @@ server, my kubernetes cluster and my dokku server:
|
|||
- hlang -> https://h.christine.website
|
||||
- mi -> https://mi.within.website
|
||||
- printerfacts -> https://printerfacts.cetacean.club
|
||||
- xesite -> https://christine.website
|
||||
- xesite -> https://xeiaso.net
|
||||
- graphviz -> https://graphviz.christine.website
|
||||
- idp -> https://idp.christine.website
|
||||
- oragono -> ircs://irc.within.website:6697/
|
||||
|
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- shell
|
||||
---
|
||||
|
||||
# The Beautiful in the Ugly
|
||||
|
||||
Functional programming is nice and all, but sometimes you just need to have
|
||||
things get done regardless of the consequences. Sometimes a dirty little hack
|
||||
will suffice in place of a branching construct. This is a story of one of these
|
||||
|
|
|
@ -6,9 +6,6 @@ tags:
|
|||
- beego
|
||||
---
|
||||
|
||||
Web Application Development with Beego
|
||||
======================================
|
||||
|
||||
Beego is a fantastic web application framework from the Go China
|
||||
community. It currently powers some of the biggest websites in China,
|
||||
and thus the world.
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
title: "My Next Life as an Imaginary Bottle of Window Cleaner"
|
||||
date: 2021-09-24
|
||||
author: Mai
|
||||
tags:
|
||||
- isekai
|
||||
- fiction
|
||||
---
|
||||
|
||||
Today was another boring day, like all the other boring days. I was almost done
|
||||
with my commute to the office, not looking forward to spending another day
|
||||
working on the same spreadsheet. I don't believe in monsters, ghosts or spirits,
|
||||
but I do believe that thing is haunted.
|
||||
|
||||
"Next stop is Broughton Junction, end of the line!"
|
||||
|
||||
That was my stop. I thought I got it easy by getting an apartment right next to
|
||||
the train, but I never thought that my job would move so far away. I got up with
|
||||
the others and walked my way to the exit of the station. The crowd was lifeless
|
||||
and dead today. The usual morning rush of the station I got on the train at had
|
||||
turned into a lazy slump towards the exit.
|
||||
|
||||
The only solace from these doldrums was the barista at the coffee shop by the
|
||||
doors. She had such a lovely smile; sometimes it was the only thing that kept me
|
||||
going. _I wonder what her name is_, I thought to myself as I breached the
|
||||
darkness of the station and was enveloped in the light of the outside world.
|
||||
Nubypool was the financial hub of the province. My work was in the Ministry of
|
||||
Accounting, taming the beast that was their spreadsheets. As I walked towards
|
||||
the entrance of the building I looked around, seeing the gray, drab skyscrapers
|
||||
around me sully the lively deep blue above them.
|
||||
|
||||
I crossed the street and walked to the double doors, but then there was a noise.
|
||||
I looked up and saw something falling towards me, then suddenly there was a loud
|
||||
noise and everything went dark.
|
||||
|
||||
The darkness persisted for a while, I couldn't touch, see or hear myself. I was
|
||||
alone in a silent hell with only my thoughts to break the sheer emptiness of it
|
||||
all. Suddenly, it hit me. _I'm dead, aren't I? I'm never going to get that
|
||||
barista's number, am I?_
|
||||
|
||||
A noise filled my awareness. I couldn't recognize it, but it came with a
|
||||
friendly presence. It felt like my best friend, mother, and more all in one. I
|
||||
felt like I knew this person intimately even though we had never spoken before.
|
||||
I could pick out that there were words, but nothing usable other than that.
|
||||
|
||||
The words stopped after a while, and that was the saddest part of the whole
|
||||
thing. I was so alone without the words, but I didn't feel like I had any
|
||||
control over when they started. They started and stopped without any indication
|
||||
of where or when they were coming from.
|
||||
|
||||
Then they started again and I knew that I needed to capitalize on this. The
|
||||
voice was going to go away if I didn't do anything about it. All I could do was
|
||||
think, so I decided to think as loud and hard as I could. I screamed in my mind.
|
||||
I would have woke the neighbors if this was in the apartment back home. Those
|
||||
thin walls would have made the entire floor wake up. I shouted and shouted like
|
||||
my life depended on it. As I shouted and screamed the darkness started to gain
|
||||
color. There was a small pinhole of light that expanded and filled my awareness
|
||||
until it grew to everywhere I could see. _Is this reincarnation?_
|
||||
|
||||
As if a blindfold had been lifted, I could finally get to see myself in some
|
||||
level of detail. I looked down and all I saw was a bright poster with what
|
||||
looked like words on it. I looked behind me and I saw what appeared to be a
|
||||
poster with more smaller words. I looked to the sides and saw what appeared to
|
||||
be clear plastic with a blue liquid in it.
|
||||
|
||||
I started panicking. I didn't know what was going on. _Aren't I supposed to be
|
||||
some kind of animal? Why am I this?_
|
||||
|
||||
The voice started again, a lot more clearly. I could pick out the words: "So
|
||||
_that's_ why they call it a 'head pressure'! Wow I don't even know how to
|
||||
describe this feeling other than that!"
|
||||
|
||||
I looked ahead and I saw a young boy, something like 18 years old. I was in some
|
||||
kind of small apartment. There was a ritual circle of some kind, I was right in
|
||||
the middle of it. Looking around there was a pentagram made out of a white and
|
||||
blue powder, cards I've never seen before and a bottle of red liquid. There was
|
||||
a mirror to the side of me though. I took a long and detailed look at myself.
|
||||
|
||||
I saw an orange nozzle look back at me. There was what appeared to be a handle
|
||||
under the nozzle, looking like it was screwed on top of a bottle of...
|
||||
|
||||
_No, this can't be!_
|
||||
|
||||
It was screwed on top of a bottle of window cleaner.
|
||||
|
||||
"I'M A BOTTLE OF WINDOW CLEANER????"
|
||||
|
||||
The boy in front of me winced and grunted, my shouting must have hurt him. I
|
||||
suddenly got a feeling of fear washing over me. I felt the tip of my nozzle
|
||||
screw itself shut and my self-image vanished from the mirror. Had I interrupted
|
||||
the ritual?
|
||||
|
||||
The boy composed himself and looked down at me. "So, you're the succubus I
|
||||
summoned? What's wrong with you?"
|
||||
|
||||
"S...succubus? I'm not a succubus, I could swear that a few days ago I was...
|
||||
well not this. I don't know what I am other than apparently..."
|
||||
|
||||
I tried to gesture at my own body but only ended up making my handle flail about
|
||||
meaninglessly, spraying a bit of blue fluid out of my nozzle. It felt like it
|
||||
had come out of my mouth. It had no taste initially, but it left a slightly sour
|
||||
taste after a moment.
|
||||
|
||||
"A bottle of window cleaner??"
|
||||
|
||||
"...What. How did this happen?"
|
||||
|
||||
"Why are you asking me? You apparently summoned me. What did you expect to get?"
|
||||
|
||||
The boy looked at me like I had lobsters crawling out of my ears. Assuming I had
|
||||
ears that were big enough for lobsters crawling out of them that is.
|
||||
|
||||
"I...what...how...okay"
|
||||
|
||||
There was suddenly a knock at the door. "SHIT!", the boy said to himself without
|
||||
saying it. He started scrambling around and frantically trying to clean things.
|
||||
|
||||
He swept up the white powder and put away the playing cards, but try as he might
|
||||
he couldn't grab me to put me away. His hand phased through me like I wasn't
|
||||
there. He got up and let the other person in. It was a pizza delivery person.
|
||||
The boy handed over some money and then took the pizza and placed it on top of a
|
||||
clear spot of his desk.
|
||||
|
||||
I suddenly found myself on top of a metal surface. I could feel something
|
||||
spinning under me and heard the soft hum of an idle fan. I had just teleported
|
||||
across the room. "W..what, why am I here?"
|
||||
|
||||
"I didn't...know that would do anything. I thought it would be nice if you were
|
||||
on top of my computer and you just appeared there." Another knock came at the
|
||||
door. There was a female voice.
|
||||
|
||||
"Shit, play it cool."
|
||||
|
||||
"I don't know how I can do anything other than what I am doing now, but okay."
|
||||
|
||||
A woman entered the room. She appeared to be in a very skimpy outfit, showing
|
||||
off her curves. She also seemed to have a pair of demonic looking wings that she
|
||||
let open in the middle of the room. The boy awkwardly made conversation with her
|
||||
for a while. I tried to get the boy's attention by spraying at him. I definitely
|
||||
got his attention. "What're you looking at, roomie? Aren't you gonna give your
|
||||
poor roomie some pizza?"
|
||||
|
||||
I didn't think she could see me. I tried spraying more. The boy looked over at
|
||||
me angrily. "Cut it out bottle, I'll throw you out with the trash if you keep
|
||||
that up!"
|
||||
|
||||
"What are you talking about? I'm not a bottle, I'm hungry." She walked over to
|
||||
the pizza and grabbed a slice, pushing the boy into his desk. She looked dead at
|
||||
me when she had her slice. I don't think she saw me. She turned around and
|
||||
bumped one of her wings into the boy, causing them to fall off. "Nooo! My
|
||||
costume!"
|
||||
|
||||
"That's what you get for wearing a succubus costume in a dorm hall."
|
||||
|
||||
She stuck her tongue out sarcastically at the boy and picked up her wing. "Okay
|
||||
sarcasm boy, you're gonna help me get this on~. If you do I may have a fun time
|
||||
planned for you~."
|
||||
|
||||
"I know what you're planning Mike. I'm not going to bang you. We agreed that I
|
||||
wouldn't before you did this."
|
||||
|
||||
"No fun."
|
||||
|
||||
Her name is _Mike_? I thought about it and decided that it was better to leave
|
||||
things be.
|
||||
|
||||
"Hey, dude, I don't really know what's going on. Where am I? Who am I? What am
|
||||
I? Are you just gonna keep me in the dark about all of this?" I tried to direct
|
||||
this to the boy with a burst of energy, spraying him to be sure I got his
|
||||
attention.
|
||||
|
||||
He looked over at me like I was cock-blocking him. I felt myself blush and
|
||||
backed off. It looks like there would be plenty of time later to get those
|
||||
questions answered.
|
||||
|
||||
"Hey Conner, when are you going to get into your costume? Did the ritual I gave
|
||||
you work?"
|
||||
|
||||
"Yeah...about that..."
|
||||
|
||||
---
|
||||
|
||||
Elsewhere at a random cleaning product factory, it was business as usual. The
|
||||
production lines were running smoothly. The trucks of cleaner continued as
|
||||
normal and every bottle was being filled at the normal rate.
|
||||
|
||||
A woman in a skimpy outfit suddenly appeared on the production line, causing one
|
||||
of the workers to hit the "emergency stop" button. The woman had a demonic aura
|
||||
about her. Her bewitching gaze stunned the factory floor. She got off the
|
||||
production line and walked out of the building, with that worker in tow;
|
||||
seemingly enamored with her. _This is going to be fun~_, she thought to herself.
|
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
title: "Site Update: The Big Domain Move To xeiaso.net"
|
||||
date: 2022-05-28
|
||||
tags:
|
||||
- dns
|
||||
---
|
||||
|
||||
Hello all!
|
||||
|
||||
If you take a look in the URL bar of your browser (or on the article URL section
|
||||
of your feed reader), you should see that there is a new domain name! Welcome to
|
||||
[xeiaso.net](https://xeiaso.net)!
|
||||
|
||||
Hopefully nothing broke in the process of moving things over, I tried to make
|
||||
sure that everything would forward over and today I'm going to explain how I did
|
||||
that.
|
||||
|
||||
I have really good SEO on my NixOS articles, and for my blog in general. I did
|
||||
not want to risk tanking that SEO when I moved domain names, so I have been
|
||||
putting this off for the better part of a year. As for why now? I got tired of
|
||||
internets complaning that the URL was "christine dot website" when I wanted to
|
||||
be called "Xe". Now you have no excuse.
|
||||
|
||||
So the first step was to be sure that everything got forwarded over to the new
|
||||
domain. After buying the domain name and setting everything up in Cloudflare
|
||||
(including moving my paid plan over), I pointed the new domain at my server and
|
||||
then set up a new NixOS configuration block to have that domain name point to my
|
||||
site binary:
|
||||
|
||||
```nix
|
||||
services.nginx.virtualHosts."xeiaso.net" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://unix:${toString cfg.sockPath}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
forceSSL = cfg.useACME;
|
||||
useACMEHost = "xeiaso.net";
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/xesite.access.log;
|
||||
'';
|
||||
};
|
||||
```
|
||||
|
||||
After that was working, I then got a list of all the things that probably
|
||||
shouldn't be redirected from. In most cases, most HTTP clients should do the
|
||||
right thing when getting a permanent redirect to a new URL. However, we live in
|
||||
a fallen world where we cannot expect clients to do the right thing. Especially
|
||||
RSS feed readers.
|
||||
|
||||
So I made a list of all the things that I was afraid to make permanent redirects
|
||||
for and here it is:
|
||||
|
||||
* `/jsonfeed` - a JSONFeed package for Go
|
||||
([docs](https://pkg.go.dev/christine.website/jsonfeed)), I didn't want to
|
||||
break builds by issuing a permanent redirect that would not match the
|
||||
[go.mod](https://tulpa.dev/Xe/jsonfeed/src/branch/master/go.mod) file.
|
||||
* `/.within/health` - the healthcheck route used by monitoring. I didn't want to
|
||||
find out if NodePing blew up on a 301.
|
||||
* `/.within/website.within.xesite/new_post` - the URL used by the [Android
|
||||
app](https://play.google.com/store/apps/details?id=website.christine.xesite)
|
||||
widget to let you know when a new post is published. I didn't want to find out
|
||||
if Android's HTTP library handles redirects properly or not.
|
||||
* `/blog.rss` - RSS feed readers are badly implemented. I didn't want to find
|
||||
out if it would break people's feeds entirely. I actually care about people
|
||||
that read this blog over RSS and I'm sad that poorly written feed readers
|
||||
punish this server so much.
|
||||
* `/blog.atom` - See above.
|
||||
* `/blog.json` - See above.
|
||||
|
||||
Now that I have the list of URLs to not forward, I can finally write the small
|
||||
bit of Nginx config that will set up permanent forwards (HTTP status code 301)
|
||||
for every link pointing to the old domain. It will look something like this:
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
return 301 https://xeiaso.net$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
<xeblog-conv name="Mara" mood="hacker">Note that it's using `$request_uri` and
|
||||
not just `$uri`. If you use `$uri` you run the risk of [CRLF
|
||||
injection](https://reversebrain.github.io/2021/03/29/The-story-of-Nginx-and-uri-variable/),
|
||||
which will allow any random attacker to inject HTTP headers into incoming
|
||||
requests. This is not a good thing to have happen, to say the
|
||||
least.</xeblog-conv>
|
||||
|
||||
So I wrote a little bit of NixOS config that automatically bridges the gap:
|
||||
|
||||
```nix
|
||||
services.nginx.virtualHosts."christine.website" = let proxyOld = {
|
||||
proxyPass = "http://unix:${toString cfg.sockPath}";
|
||||
proxyWebsockets = true;
|
||||
}; in {
|
||||
locations."/jsonfeed" = proxyOld;
|
||||
locations."/.within/health" = proxyOld;
|
||||
locations."/.within/website.within.xesite/new_post" = proxyOld;
|
||||
locations."/blog.rss" = proxyOld;
|
||||
locations."/blog.atom" = proxyOld;
|
||||
locations."/blog.json" = proxyOld;
|
||||
locations."/".extraConfig = ''
|
||||
return 301 https://xeiaso.net$request_uri;
|
||||
'';
|
||||
forceSSL = cfg.useACME;
|
||||
useACMEHost = "christine.website";
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/xesite_old.access.log;
|
||||
'';
|
||||
};
|
||||
```
|
||||
|
||||
This will point all the scary paths to the site itself and have
|
||||
`https://christine.website/whatever` get forwarded to
|
||||
`https://xeiaso.net/whatever`, this makes sure that every single link that
|
||||
anyone has ever posted will get properly forwarded. This makes link rot
|
||||
literally impossible, and helps ensure that I keep my hard-earned SEO.
|
||||
|
||||
I also renamed my email address to `me@xeiaso.net`. Please update your address
|
||||
books and spam filters accordingly. Also update my name to `Xe Iaso` if you
|
||||
haven't already.
|
||||
|
||||
I've got some projects in the back burner that will make this blog even better!
|
||||
Stay tuned and stay frosty.
|
||||
|
||||
What was formerly known as the "christine dot website cinematic universe" is now
|
||||
known as the "xeiaso dot net cinematic universe".
|
|
@ -4,8 +4,6 @@ date: 2018-11-29
|
|||
series: conlangs
|
||||
---
|
||||
|
||||
# Blind Men and an Elephant
|
||||
|
||||
or
|
||||
|
||||
# le'i ka na viska kakne ku e le xanto
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- 100th-post
|
||||
---
|
||||
|
||||
# Blog Feature: Art Gallery
|
||||
|
||||
I have just implemented support for my portfolio site to also function as an art
|
||||
gallery. See all of my posted art [here](/gallery).
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- borgbackup
|
||||
---
|
||||
|
||||
# How to Set Up Borg Backup on NixOS
|
||||
|
||||
[Borg Backup](https://www.borgbackup.org/) is a encrypted, compressed,
|
||||
deduplicated backup program for multiple platforms including Linux. This
|
||||
combined with the [NixOS options for configuring
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- blender
|
||||
---
|
||||
|
||||
# How I Converted my Brain fMRI to a 3D Model
|
||||
|
||||
AUTHOR'S NOTE: I just want to start this out by saying I am not an expert, and
|
||||
nothing in this blogpost should be construed as medical advice. I just wanted
|
||||
to see what kind of pretty pictures I could get out of an fMRI data file.
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
---
|
||||
title: You Win, Broken Database Schemas
|
||||
date: 2022-01-10
|
||||
tags:
|
||||
- rant
|
||||
---
|
||||
|
||||
There is [no software that correctly handles
|
||||
names](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/)
|
||||
that exists on this planet. One of the major things I have bashed my head into
|
||||
as of late is the assumption that people have a first and a last name. The first
|
||||
name is usually what identifies the person, and the last name usually identifies
|
||||
the family.
|
||||
|
||||
I have wanted to use `Xe` as my name places (no last name, like Socrates), but
|
||||
everyone has broken database schemas that make it impossible. These schemas
|
||||
usually look like this:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS people
|
||||
( id VARCHAR PRIMARY KEY DEFAULT (uuid4())
|
||||
, first_name VARCHAR NOT NULL
|
||||
, last_name VARCHAR NOT NULL
|
||||
-- draw the rest of the owl
|
||||
);
|
||||
```
|
||||
|
||||
And as a result things like `Xe` (no last name) cannot fit into this schema. I
|
||||
have found out the depth of this shitshow while trying to use my handle as my
|
||||
name on newly registered account things and the amount of stuff that breaks or
|
||||
works in weird ways is _staggering_. Email salutations look like this:
|
||||
|
||||
> Hello Xe ,
|
||||
|
||||
Forms will break if I don't put a last name in the field. The assumptions about
|
||||
names are _so deep_ that it's rapidly becoming not worth it to only have my name
|
||||
as `Xe`. Not to mention [overzealous journalists that will argue with you over
|
||||
what your name is due to name
|
||||
collisions](https://twitter.com/theprincessxena/status/1479197000667181061?s=20).
|
||||
|
||||
You win, broken database schemas. I give up trying to deal with you to encode my
|
||||
name correctly. You just don't let me and I am tired of fighting it, opening
|
||||
support tickets and arguing with people over what my name is. I give in. I'm
|
||||
going to use a last name for my handle, which is absolutely ridiculous, but here
|
||||
we are.
|
||||
|
||||
It took me a few hours to dig through ideas over the weekend and today, but I
|
||||
think I have found something satisfactory enough that I can keep it for the long
|
||||
haul: [Iaso](https://en.wikipedia.org/wiki/Iaso) (ai-uh-so, /aÉŞ.É™.soĘŠ/), the
|
||||
minor Greek goddess of recovering from illness.
|
||||
|
||||
Hopefully I don't have to deal with professional issues as a result of me trying
|
||||
to be more true to myself about my identity. At the very least I want very
|
||||
little to do with the last name that I was born into. Some day that name will be
|
||||
removed from the last database with it set, but today is not that day.
|
||||
|
||||
If you work on systems that handle names, please, please, please take the time
|
||||
to reconsider if you actually need to deal with a last name for more reason than
|
||||
it's the cultural standard. There are valid reasons to have a mononym, and by
|
||||
supporting mononyms you will make people's lives easier.
|
||||
|
||||
Until then, I am `Xe Iaso`. Let's see where this phase of the identity
|
||||
experiment goes. It's still really complicated. Anyone who claims to have their
|
||||
identity figured out is either in denial or stopped digging into it for the time
|
||||
being. The rabbit hole truly never ends.
|
||||
|
||||
The main thing I don't like about this name is how ambiguous it shows up in
|
||||
sans-serif fonts:
|
||||
|
||||
<div style="font-family:sans-serif">
|
||||
|
||||
Xe Iaso
|
||||
|
||||
</div>
|
||||
|
||||
It looks like `Xe laso`. I've edited my email signature to try and compensate
|
||||
for this:
|
||||
|
||||
```
|
||||
Xe Iaso (zi ai-uh-so)
|
||||
https://xeiaso.net
|
||||
|
||||
.i la budza pu cusku lu
|
||||
<<.i ko snura .i ko kanro
|
||||
.i ko panpi .i ko gleki
|
||||
```
|
||||
|
||||
Let's see if that helps. It will probably look bad when things are put into
|
||||
sans-serif fonts, but what can you do lol.
|
||||
|
||||
---
|
||||
|
||||
Also I would _prefer_ you call me `Xe` from now on when possible. This conflicts
|
||||
with and supercedes suggestions I made in [this article](/blog/xe-2021-08-07). I
|
||||
consider most of that experiment to have worked out and I am going into the next
|
||||
phase, albeit less "pure" than I wanted.
|
||||
|
||||
Thank you for sticking with this blog. This started out as a place for me to get
|
||||
better at writing but has rapidly turned into something that has helped me
|
||||
explore my identity in ways that I never would have thought it would. Thanks for
|
||||
following the rabbit hole. Thank you for supporting me being more authentic to
|
||||
myself about who I am. Your support means more than you possibly will know.
|
||||
|
||||
I wonder if my SEO craft is strong enough to get me high on the list of google
|
||||
results for `Iaso`.
|
|
@ -5,8 +5,6 @@ tags:
|
|||
- career
|
||||
---
|
||||
|
||||
# Advice to People Nurturing a Career in Computering
|
||||
|
||||
Computering, or making computers do things in exchange for money, can be a
|
||||
surprisingly hard field to break into as an outsider. There's lots of jargon,
|
||||
tool holy wars, flamewars about the "right" way to do things and a whole host
|
||||
|
@ -38,7 +36,7 @@ Your website should include at least the following things:
|
|||
- Links to or words about projects of yours that you are proud of
|
||||
- Some contact information (an email address is a good idea too)
|
||||
|
||||
If you feel comfortable doing so, I'd also suggest putting your [resume](https://christine.website/resume)
|
||||
If you feel comfortable doing so, I'd also suggest putting your [resume](https://xeiaso.net/resume)
|
||||
on this site too. Even if it's just got your foodservice jobs or education
|
||||
history (including your high school diploma if need be).
|
||||
|
||||
|
@ -49,7 +47,7 @@ not.
|
|||
## Make a Tech Blog On That Site
|
||||
|
||||
This has been the single biggest thing to help me grow professionally. I regularly
|
||||
put [articles](https://christine.website/blog) on my blog, sometimes not even about
|
||||
put [articles](https://xeiaso.net/blog) on my blog, sometimes not even about
|
||||
technology topics. Even if you are writing about your take on something people have
|
||||
already written about, it's still good practice. Your early posts are going to be
|
||||
rough. It's normal to not be an expert when starting out in a new skill.
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
---
|
||||
title: Change
|
||||
date: 2021-10-20
|
||||
tags:
|
||||
- enby
|
||||
- trans
|
||||
---
|
||||
|
||||
[Content warning: this post talks about the transgender/nonbinary coming out of
|
||||
the closet experience. If you are not in the best headspace for that, feel free
|
||||
to skip this post until you're in a better headspace. This post isn't going to
|
||||
randomly vanish. It will be there when you're ready. There are some descriptions
|
||||
of subconscious body functions and bodily fluids that may gross some people
|
||||
out.](conversation://Cadey/enby)
|
||||
|
||||
Coming out as transgender/nonbinary to someone you care about one of the most
|
||||
terrifying things you can do. At least it feels that way, it feels like things
|
||||
are going to change and you'll lose that person. It can be gut-wrenching,
|
||||
especially for family.
|
||||
|
||||
For me the scariest part of this whole thing has been the change in how people
|
||||
see me. It can be a huge abrupt difference for some people, and the unknowns in
|
||||
how people will react to that can make you paralyzed with fear. So, let's look
|
||||
at change a little.
|
||||
|
||||
[Annoyingly, the same kinds of people that get upset about someone changing
|
||||
their name and pronouns for coming out as transgender/nonbinary are _instantly_
|
||||
and _immediately_ tolerant of someone changing their last name for marriage and
|
||||
"get used to it" almost instantly.](conversation://Cadey/facepalm)
|
||||
|
||||
Life is a constant change. Stop for a moment right now and feel your body. Feel
|
||||
how the pressure in your chest changes as your lungs subconsciously inhale and
|
||||
exhale. If you have a watch, look at the seconds hand (or equivalent digital
|
||||
display) and watch it tick forward for a bit. Change is constant, yet still
|
||||
continuously moving forward. Even though the change is happening though,
|
||||
everything is still roughly the same as it was before. Blood continues to move
|
||||
through your body, constantly cycling its oxygen with other parts, but it
|
||||
continues.
|
||||
|
||||
Coming out to my parents was one of the most terrifying things I have ever done.
|
||||
I was nervous beyond belief. I hardly ate that day I hit send. I turned off my
|
||||
phone after doing it and got lost in a game that I liked playing. The real
|
||||
reason it was so scary to me though is that I had already tried to come out to
|
||||
them in the past but I was shut down.
|
||||
|
||||
Middle school was rough for me. I don't really remember much of it (other than
|
||||
they banned high fives for "gang activity"), but that was when my parents found
|
||||
my diary app. I don't remember why they were going through my laptop (I grew up
|
||||
in one of _those_ kinds of Jesus freak households), but they found it somehow
|
||||
and my entries where I was questioning my gender came to their attention and
|
||||
they confronted me about it. I was not ready at all. I was completely blindsided
|
||||
by it. That attempt to come out failed and I was put into Christian
|
||||
"counseling". I was pushed deep back into the closet and I still have trouble
|
||||
writing down my thoughts in a journal to this day.
|
||||
|
||||
So that day I hit "send" on [the
|
||||
email](https://xeiaso.net/blog/coming-out-2015-12-01) was mortally
|
||||
terrifying. All that fear from so long ago came raging up to the surface and I
|
||||
was left in a crying and vulnerable state. However it ended up being a good kind
|
||||
of cry, the healing kind.
|
||||
|
||||
My relationship with my parents (and later my siblings) has deteriorated since,
|
||||
and not just for religious differences. However, I am fine. I am still healing
|
||||
and I probably will be healing for a long time and I have accepted that. In
|
||||
place, I have found something more powerful to put in their place. I have found
|
||||
a new family of choice.
|
||||
|
||||
[For the parents that read this blog, please do not repeat this kind of
|
||||
suffering if you can avoid it. I don't want anyone else to suffer the way I have
|
||||
if I can help to avoid it.](conversation://Cadey/enby)
|
||||
|
||||
This was a huge change, but it ended up being for the better. That change was a
|
||||
tool to help me live a better life surrounded by the people I wanted to be
|
||||
around as opposed to the people I inherited.
|
||||
|
||||
There's an idiom that comes to mind, something that is in the "completely
|
||||
misunderstood" brand of idioms: "blood is thicker than water".
|
||||
It's often used by people to emphasize the importance of familial relationships
|
||||
over friendships or the like (family is the "blood" part of that idiom, and
|
||||
friendships are the "water" part). The full form of the idiom is closer to this:
|
||||
|
||||
> The blood of the covenant is thicker than the water of the womb
|
||||
|
||||
This overall sentiment is [commonly interpreted by Christian
|
||||
scholars](https://www.blueletterbible.org/Comm/murray_andrew/two/two09.cfm) to
|
||||
have a meaning closer to "the bond between Jesus and someone who chooses to
|
||||
believe in Him is stronger than the bond between family members", however we can
|
||||
afford to interpret this differently for the sake of this message.
|
||||
|
||||
The bonds you choose are stronger than the bonds you inherited. The bonds I have
|
||||
with my friends, my husband, my closest companions and all those who I keep
|
||||
close to me are stronger than the bonds with my family will ever be.
|
||||
|
||||
In a way, coming out as transgender to people and that level of associated
|
||||
change has become a _tool_ to help me figure out who really cares about me and
|
||||
who I should bother keeping around me. It's my life. I can live it as honestly,
|
||||
openly and real as I want to. I don't have to justify it to anyone but myself.
|
||||
|
||||
You don't really have to justify this level of change to anyone else but
|
||||
yourself either. It'll let you know who your real friends are, for better and
|
||||
for worse. You don't have to keep anyone around you that can't accept you for
|
||||
who you are. Your family of choice will _always_ have stronger bonds than your
|
||||
family of origin.
|
||||
|
||||
<center>
|
||||
<picture>
|
||||
<source srcset="/static/blog/change/the-dude-dither.avif" type="image/avif">
|
||||
<source srcset="/static/blog/change/the-dude-dither.webp" type="image/webp">
|
||||
<img src="/static/blog/change/the-dude-dither.png" alt="The dude abides">
|
||||
</picture>
|
||||
</center>
|
||||
|
||||
The Dude abides, so will you. Change as a result of coming out can be a good
|
||||
thing as much as it can be a bad thing. Don't let inherent negativity biases
|
||||
blind you to that.
|
|
@ -5,8 +5,6 @@ thanks: CelestialBoon
|
|||
series: magick
|
||||
---
|
||||
|
||||
# Chaos Magick Debugging
|
||||
|
||||
Belief is a powerful thing. Beliefs are the foundations of everyone's points of view, and the way they interpret reality. Belief is what allows people to create the greatest marvels of technology, the most wondrous worlds of imagination, and the most oppressive religions.
|
||||
|
||||
But at the core, what *is* a belief, other than the sheer tautology of *what a person believes*?
|
||||
|
|
|
@ -9,8 +9,6 @@ tags:
|
|||
- garlic
|
||||
---
|
||||
|
||||
# Chicken Stir Fry
|
||||
|
||||
This recipe was made up by me and my fiancé. We just sorta winged it every time
|
||||
we made it until we found something that was easy to cook and tasty. We make
|
||||
this every week or so.
|
||||
|
|
|
@ -5,9 +5,6 @@ tags:
|
|||
- cinemaquestria
|
||||
---
|
||||
|
||||
CinemaQuestria Orchestration
|
||||
============================
|
||||
|
||||
### Or: Continuous Defenstration in a Container-based Ecosystem
|
||||
|
||||
I've been a core member of the staff for [CinemaQuestria](http://cinemaquestria.com)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
title: "Book Release: Closed Projects"
|
||||
date: 2022-03-24
|
||||
tags:
|
||||
- shortstory
|
||||
- fiction
|
||||
- retrospective
|
||||
---
|
||||
|
||||
Closed Projects is a retelling of [a four-part series](/blog/series/freenode) on
|
||||
my blog where I process the events that lead to the death of freenode, the
|
||||
largest IRC network for peer-directed projects.
|
||||
|
||||
freenode was the reason that I managed to get into tech. Without freenode I
|
||||
would be a vastly different person today. The death of freenode last year
|
||||
brought up many lingering memories and emotions. I talk about my history with
|
||||
freenode, the events that happened in the wake of its death and how a new
|
||||
community took its place.
|
||||
|
||||
Each part of this story is written by weaving the narrative of the last
|
||||
caretaker trying to protect the discussion halls against the darkness, and
|
||||
things continue as the darkness gets more crafty and clever.
|
||||
|
||||
I have included versions of this for all common eBook reader devices and
|
||||
formats. I have tested this on my Kindle Oasis and iPad Pro, but I see no reason
|
||||
that at least one of these formats wouldn't work for you.
|
||||
|
||||
<iframe frameborder="0" src="https://itch.io/embed/1454153?dark=true" width="552" height="167"><a href="https://withinstudios.itch.io/closed-projects">Closed Projects by Within</a></iframe>
|
||||
|
||||
If you are a [Patreon supporter](https://patreon.com/cadey), you can get this
|
||||
for free by clicking [this
|
||||
link](https://withinstudios.itch.io/closed-projects/patreon-access).
|
||||
|
||||
If you are a part of a marginalized group and cannot afford this but want to
|
||||
read it anyways, please [contact me](/contact).
|
||||
|
||||
Thank you for reading what I put out to the world. I only hope I can continue to
|
||||
create and inspire you.
|
|
@ -3,8 +3,6 @@ title: My Magical Adventure With cloud-init
|
|||
date: 2021-06-04
|
||||
---
|
||||
|
||||
# My Magical Adventure With cloud-init
|
||||
|
||||
> "If I had a world of my own, everything would be nonsense. Nothing would be
|
||||
> what it is, because everything would be what it isn't. And contrary wise, what
|
||||
> is, it wouldn't be. And what it wouldn't be, it would. You see?"
|
||||
|
|
|
@ -5,8 +5,6 @@ tags:
|
|||
- ipad
|
||||
---
|
||||
|
||||
# Coding on an iPad
|
||||
|
||||
As people notice, I am an avid user of Emacs for most of my professional and
|
||||
personal coding. I have things set up such that the center of my development
|
||||
environment is a shell (eshell), and most of my interactions are with emacs
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2020-08-22
|
|||
series: colemak
|
||||
---
|
||||
|
||||
# Colemak Layout - First Week
|
||||
|
||||
A week ago I posted the last post in this series where I announced I was going
|
||||
all colemak all the time. I have not been measuring words per minute (to avoid
|
||||
psyching myself out), but so far my typing speed has gone from intolerably slow
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2020-08-15
|
|||
series: colemak
|
||||
---
|
||||
|
||||
# Colemak Layout - Beginning
|
||||
|
||||
I write a lot. On average I write a few kilobytes of text per day. This has been
|
||||
adding up and is taking a huge toll on my hands, especially considering the
|
||||
Covid situation. Something needs to change. I've been working on learning a new
|
||||
|
|
|
@ -5,9 +5,6 @@ tags:
|
|||
- personal
|
||||
---
|
||||
|
||||
Coming Out
|
||||
==========
|
||||
|
||||
I'd like to bring up something that has been hanging over my head for a
|
||||
long time. This is something I did try (and fail) to properly express way
|
||||
back in middle school, but now I'd like to get it all of my chest and let
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- vrchat
|
||||
---
|
||||
|
||||
# My Convoluted VRChat Google Meet Setup
|
||||
|
||||
Recently the place I work for sent us all VR headsets. I decided to see what it
|
||||
would take to use that headset to make my camera show a virtual avatar instead
|
||||
of my meat body face. This is the story of my journey through chaining things
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
title: COVID Burnout
|
||||
date: 2021-09-25
|
||||
---
|
||||
|
||||
NOTE: This was written out in
|
||||
[longhand](https://twitter.com/theprincessxena/status/1441842150824718337?s=21)
|
||||
in my diary. This post was converted to text using iPadOS 15's handwriting to
|
||||
text recognition. I hope I have cleared up all of the major errors in the
|
||||
conversion. My handwriting is horrible.
|
||||
|
||||
---
|
||||
|
||||
I am an introvert. I usually spend a lot of time in my cave. most of my work was
|
||||
alreary done remotely, when I first found out about the COVID-19 pandemic, I
|
||||
thought there would be at most 4-8 weeks of hardcore lockdown and then it would
|
||||
die out. Then life would go back to normal and I would be able to see my friends
|
||||
at conventions during the summer.
|
||||
|
||||
As of the time of writing this post, it is currently the 84th week OF COVID
|
||||
being a major presence in how I handle daily life. I am exhausted, I was
|
||||
scheduled to give talks at two conventions that were canceled, meet ups with
|
||||
friends at places across the us and Canada were postponed into oblivion. My
|
||||
relationship with my parents has fractured into no-contact. I feel powerless to
|
||||
do anything more to stop this.
|
||||
|
||||
I am the most connected I have ever been and I am the lonliest I have ever been.
|
||||
Most of the people I talk to are people I have never met in person, even my
|
||||
coworkers. My manager is someone I talk with near daily yet have never seen
|
||||
without the aid of video conferencing.
|
||||
|
||||
This is exhausting. I hate it. My Netflix queue is empty. I feel so alone.
|
||||
|
||||
This post doesn't have a message or moral.
|
|
@ -6,9 +6,6 @@ tags:
|
|||
- frontend
|
||||
---
|
||||
|
||||
Crazy Experiment: Ship the Frontend as an asar document
|
||||
=======================================================
|
||||
|
||||
Today's crazy experiment is using an [asar archive](https://github.com/electron/asar) for shipping around
|
||||
and mounting frontend Javascript applications. This is something I feel is worth doing because it allows
|
||||
the web frontend developer (or team) give the backend team a single "binary" that can be dropped into the
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- coc
|
||||
---
|
||||
|
||||
# [Creator's Code](https://github.com/Xe/creators-code)
|
||||
|
||||
I feel there is a large problem in the industry I have found myself in. There is,
|
||||
unfortunately, a need for codes of behavioral conduct to help arrange and align
|
||||
collaboration across so many cultural and ideological barriers, as well as
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2018-11-21
|
|||
series: dreams
|
||||
---
|
||||
|
||||
# My Experience Cursing Out God
|
||||
|
||||
This was a hell of a dream.
|
||||
|
||||
It was a simple landscape: a hill, a sky, a sun, a distance, naturalistic buildings dotting a small village to the east. I noticed that I felt different somehow, like I was less chained down. A genderless but somehow masculine moved and stood next to me, gesturing towards me: "It's beautiful isn't it? The village has existed like this for thousands of years in perfect harmony with its world. Even though there's volcano eruptions every decade that burn everything down. It's been nine years and 350 days, but they aren't keeping track. How does that thought make you feel, Creator?"
|
||||
|
|
|
@ -5,8 +5,6 @@ thanks: Sygma
|
|||
series: magick
|
||||
---
|
||||
|
||||
# Death
|
||||
|
||||
Death is a very misunderstood card in Tarot, but not for the reasons you'd think. Societally, many people think that this life is the only shot at existence they get. Afterwards, there is nothing. Nonexistence. Oblivion. This makes death a very touchy subject for a lot of people, so much so it forms a social taboo and an unhealthy relationship with death. People start seeing death as something they need to fight back and hold away by removing what makes themselves human, just to hold off what they believe is their obliteration.
|
||||
|
||||
Tarot does not see death in this way. Death, the skeleton knight wearing armor, does not see color, race or creed, thus he is depicted as a skeleton. He is riding towards a child and another younger person. The sun is rising in the distance, but even it cannot stop Death. Nor can royalty, as shown by the king under him, dead.
|
||||
|
|
|
@ -8,8 +8,6 @@ tags:
|
|||
- what
|
||||
---
|
||||
|
||||
# Death Stranding Review
|
||||
|
||||
NOTE: There's gonna be spoilers here. Do not read if you are not okay with this.
|
||||
For a summary of the article without spoilers, this game is 10 out of 10 game of the
|
||||
year 2019 for me.
|
||||
|
|
|
@ -3,9 +3,6 @@ title: Dependency Hell
|
|||
date: 2014-11-20
|
||||
---
|
||||
|
||||
Dependency Hell
|
||||
===============
|
||||
|
||||
A lot of the problem that I have run into when doing development with
|
||||
nearly any stack I have used is dependency management. This relatively
|
||||
simple-looking problem just becomes such an evil, evil thing to tackle.
|
||||
|
|
|
@ -5,8 +5,6 @@ tags:
|
|||
- release
|
||||
---
|
||||
|
||||
# Deprecation Notice: Elemental-IRCd
|
||||
|
||||
[Elemental-IRCd](https://github.com/Elemental-IRCd/elemental-ircd) is a scalable, lightweight, high-performance IRC daemon written in C with heritage in the original IRC daemon. It is a fork of the now-defunct ShadowIRCD and sought to continue in the direction ShadowIRCD was headed. This software has scaled to support live chat for thousands of users at once in one->one and one->many groups. Working on this software has legitimately been a vital driving force to my career and skill balance between administration, development, moderation and operations of distirbuted communities at scale. Without this software, my closest friends (and even my fiancé) would be strangers to me.
|
||||
|
||||
However, the result is something I don't know if I can continue to keep maintaining. It's been through a lot. The code has been through so many hands, some files had different licenses compared to the rest of the software. It is a patchwork of patches on top of a roughly solid core, and it's become a burden to maintain.
|
||||
|
|
|
@ -5,9 +5,6 @@ tags:
|
|||
- release
|
||||
---
|
||||
|
||||
Instant Development Environments in Docker
|
||||
==========================================
|
||||
|
||||
I have been using a few shell scripts for turbocharging development
|
||||
using Docker and today I have released the first version of a simple
|
||||
tool I call "[dev](https://github.com/Xe/dev)". Usage is very very simple.
|
||||
|
|
|
@ -8,8 +8,6 @@ tags:
|
|||
- kernel
|
||||
---
|
||||
|
||||
# How I Implemented /dev/printerfact in Rust
|
||||
|
||||
Kernel mode programming is a frightful endeavor. One of the big problems with it
|
||||
is that C is really your only option on Linux. C has many historical problems
|
||||
with it that can't really be fixed at this point without radically changing the
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- witchcraft
|
||||
---
|
||||
|
||||
# Dhall for Kubernetes
|
||||
|
||||
Kubernetes is a surprisingly complicated software package. Arguably, it has to
|
||||
be that complicated as a result of the problems it solves being complicated; but
|
||||
managing yaml configuration files for Kubernetes is a complicated task. [YAML][yaml]
|
||||
|
@ -23,7 +21,7 @@ named [dyson][dyson] in order to help me manage Terraform as well as create
|
|||
Kubernetes manifests from [a template][template]. This works for the majority of
|
||||
my apps, but it is difficult to extend at this point for a few reasons:
|
||||
|
||||
[cultk8s]: https://christine.website/blog/the-cult-of-kubernetes-2019-09-07
|
||||
[cultk8s]: https://xeiaso.net/blog/the-cult-of-kubernetes-2019-09-07
|
||||
[dyson]: https://github.com/Xe/within-terraform/tree/master/dyson
|
||||
[template]: https://github.com/Xe/within-terraform/blob/master/dyson/src/dysonPkg/deployment_with_ingress.yaml
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2018-08-27
|
|||
for: Sam
|
||||
---
|
||||
|
||||
# Died to Save Me
|
||||
|
||||
People often get confused
|
||||
when I mention the fact that I
|
||||
consider myself before I
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
---
|
||||
title: Writing Coherently At Scale
|
||||
date: 2022-06-29
|
||||
tags:
|
||||
- writing
|
||||
vod:
|
||||
youtube: https://youtu.be/pDOoqqu06-8
|
||||
twitch: https://www.twitch.tv/videos/1513874389
|
||||
---
|
||||
|
||||
As someone who does a lot of writing, I have been asked how to write about
|
||||
things. I have been asked about it enough that I am documenting this here so you
|
||||
can all understand my process. This is not a prescriptive system that you must
|
||||
do in order to make Quality Content™️, this is what I do.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="coffee">I honestly have no idea if this is a
|
||||
"correct" way of doing things, but it seems to work well enough. Especially so
|
||||
if you are reading this.</xeblog-conv>
|
||||
|
||||
<xeblog-hero file="great-wave-cyberpunk" prompt="the great wave off of kanagawa, cyberpunk, hanzi inscription"></xeblog-hero>
|
||||
|
||||
## The Planning Phase
|
||||
|
||||
To start out the process of writing about something, I usually like to start
|
||||
with the end goal in mind. If I am writing about an event or technology thing,
|
||||
I'll start out with a goal that looks something like this:
|
||||
|
||||
> Explain a split DNS setup and its advantages and weaknesses so that people can
|
||||
> make more informed decisions about their technical setups.
|
||||
|
||||
It doesn't have to be very complicated or intricate. Most of the complexity
|
||||
comes up naturally during the process of writing the intermediate steps. Think
|
||||
about the end goal or what you want people to gain from reading the article.
|
||||
|
||||
I've also found it helps to think about the target audience and assumed skills
|
||||
of the reader. I'll usually list out the kind of person that would benefit from
|
||||
this the most and how it will help them. Here's an example:
|
||||
|
||||
> The reader is assumed to have some context about what DNS is and wants to help
|
||||
> make their production environment more secure, but isn't totally clear on how
|
||||
> it helps and what tradeoffs are made.
|
||||
|
||||
State what the reader is to you and how the post benefits them. Underthink it.
|
||||
It's tempting to overthink this, but really don't. You can overthink the
|
||||
explanations later.
|
||||
|
||||
### The Outline
|
||||
|
||||
Once I have an end goal and the target audience in mind, then I make an outline
|
||||
of what I want the post to contain. This outline will have top level items for
|
||||
generic parts of the article or major concepts/steps and then I will go in and
|
||||
add more detail inside each top level item. Here is an example set of top level
|
||||
items for that split DNS post:
|
||||
|
||||
```markdown
|
||||
- Introduction
|
||||
- Define split DNS
|
||||
- How split DNS is different
|
||||
- Where you can use split DNS
|
||||
- Advantages of split DNS
|
||||
- Tradeoffs of split DNS
|
||||
- Conclusion
|
||||
```
|
||||
|
||||
Each step should build on the last and help you reach towards the end goal.
|
||||
|
||||
After I write the top level outline, I start drilling down into more detail. As
|
||||
I drill down into more detail about a thing, the bullet points get nested
|
||||
deeper, but when topics change then I go down a line. Here's an example:
|
||||
|
||||
```markdown
|
||||
- Introduction
|
||||
- What is DNS?
|
||||
- Domain Name Service
|
||||
- Maps names to IP addresses
|
||||
- Sometimes it does other things, but we're not worrying about that today
|
||||
- Distributed system
|
||||
- Intended to have the same data everywhere in the world
|
||||
- It can take time for records to be usable from everywhere
|
||||
```
|
||||
|
||||
Then I will go in and start filling in the bullet tree with links and references
|
||||
to each major concept or other opinions that people have had about the topic.
|
||||
For example:
|
||||
|
||||
```markdown
|
||||
- Introduction
|
||||
- What is DNS?
|
||||
- Domain Name Service
|
||||
- https://datatracker.ietf.org/doc/html/rfc1035
|
||||
- Maps names to IP addresses
|
||||
- Sometimes it does other things, but we're not worrying about that today
|
||||
- Distributed system
|
||||
- Intended to have the same data everywhere in the world
|
||||
- It can take time for records to be usable from everywhere
|
||||
- https://jvns.ca/blog/2021/12/06/dns-doesn-t-propagate/
|
||||
```
|
||||
|
||||
These help me write about the topic and give me links to add to the post so that
|
||||
people can understand more if they want to. You should spend most of your time
|
||||
writing the outline. The rest is really just restating the outline in sentences.
|
||||
|
||||
## Writing The Post
|
||||
|
||||
After each top level item is fleshed out enough, I usually pick somewhere to
|
||||
start and add some space after a top level item. Then I just start writing. Each
|
||||
top level item usually maps to a few paragraphs / a section of the post. I
|
||||
usually like to have each section have its own little goal / context to it so
|
||||
that readers start out from not understanding something and end up understanding
|
||||
it better. Here's an example:
|
||||
|
||||
> If you have used a computer in the last few decades or so, you have probably
|
||||
> used the Domain Name Service (DNS). DNS maps human-readable names (like
|
||||
> `google.com`) to machine-readable IP addresses (like `182.48.247.12`). Because
|
||||
> of this, DNS is one of the bedrock protocols of the modern internet and it
|
||||
> usually is the cause of most failures in big companies.
|
||||
>
|
||||
> DNS is a globally distributed system without any authentication or way to
|
||||
> ensure that only authorized parties can query IP addresses for specific domain
|
||||
> names. As a consequence of this, this means that anyone can get the IP address
|
||||
> of a given server if they have the DNS name for it. This also means that
|
||||
> updating a DNS record can take a nontrivial amount of time to be visible from
|
||||
> everywhere in the world.
|
||||
>
|
||||
> Instead of using public DNS records for internal services, you can set up a
|
||||
> split DNS configuration so that you run an internal DNS server that has your
|
||||
> internal service IP addresses obscured away from the public internet. This
|
||||
> means that attackers can't get their hands on the IP addresses of your
|
||||
> services so that they are harder to attack. In this article, I'm going to
|
||||
> spell out how this works, the advantages of this setup, the tradeoffs made in
|
||||
> the process and how you can implement something like this for yourself.
|
||||
|
||||
In the process of writing, I will find gaps in the outline and just fix it by
|
||||
writing more words than the outline suggested. This is okay, and somewhat
|
||||
normal. Go with the flow.
|
||||
|
||||
I expand each major thing into its component paragraphs and will break things up
|
||||
into sections with markdown headers if there is a huge change in topics. Adding
|
||||
section breaks can also help people stay engaged with the post. Giant walls of
|
||||
text are hard to read and can make people lose focus easily.
|
||||
|
||||
Another trick I use to avoid my posts being giant walls of text is what I call
|
||||
"conversation snippets". These look like this:
|
||||
|
||||
<xeblog-conv name="Mara" mood="hacker">These are words and I am saying
|
||||
them!</xeblog-conv>
|
||||
|
||||
I use them for both creating [Socratic
|
||||
dialogue](https://en.wikipedia.org/wiki/Socratic_dialogue) and to add prose
|
||||
flair to my writing. I am more of a prose writer [by
|
||||
nature](https://xeiaso.net/blog/the-oasis), and I find that this mix allows me
|
||||
to keep both technical and artistic writing up to snuff.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="enby">Amusingly, I get asked if the characters
|
||||
in my blog are separate people all giving their input into things. They are
|
||||
characters, nothing more. If you ever got an impression otherwise, then I have
|
||||
done my job as a writer _incredibly well_.</xeblog-conv>
|
||||
|
||||
Just flesh things out and progressively delete parts of the outline as you go.
|
||||
It gets easier.
|
||||
|
||||
### Writing The Conclusion
|
||||
|
||||
I have to admit, I really suck at writing conclusions. They are annoying for me
|
||||
to write because I usually don't know what to put there. Sometimes I won't even
|
||||
write a conclusion at all and just end the article there. This doesn't always
|
||||
work though.
|
||||
|
||||
A lot of the time when I am describing how to do things I will end the article
|
||||
with a "call to action". This is a few sentences that encourages the reader to
|
||||
try the thing that I've been writing about out for themselves. If I was turning
|
||||
that split DNS article from earlier into a full article, the conclusion
|
||||
could look something like this:
|
||||
|
||||
> ---
|
||||
>
|
||||
> If you want an easy way to try out a split DNS configuration, install
|
||||
> [Tailscale](https://tailscale.com/) on a couple virtual machines and enable
|
||||
> [MagicDNS](https://tailscale.com/kb/1081/magicdns/). This will set up a split
|
||||
> DNS configuration with a domain that won't resolve globally, such as
|
||||
> `hostname.example.com.beta.tailscale.net`, or just `hostname` for short.
|
||||
>
|
||||
> I use this in my own infrastructure constantly. It has gotten to the point
|
||||
> where I regularly forget that Tailscale is involved at all, and become
|
||||
> surprised when I can't just access machines by name.
|
||||
>
|
||||
> A split DNS setup isn't a security feature (if anything, it's more of an
|
||||
> obscurity feature), but you can use it to help administrate your systems by
|
||||
> making your life easier. You can update records on your own schedule and you
|
||||
> don't have to worry about outside attackers getting the IP addresses of your
|
||||
> services.
|
||||
|
||||
I don't like giving the conclusion a heading, so I'll usually use a [horizontal
|
||||
rule (`---` or `<hr
|
||||
/>`)](https://www.coffeecup.com/help/articles/what-is-a-horizontal-rule/) to
|
||||
break it off.
|
||||
|
||||
---
|
||||
|
||||
This is how I write about things. Do you have a topic in mind that you have
|
||||
wanted to write about for a while? Try this system out! If you get something
|
||||
that you like and want feedback on how to make it shine, email me at
|
||||
`iwroteanarticle at xeserv dot us` with either a link to it or the draft
|
||||
somehow. I'll be sure to read it and reply back with both what I liked and some
|
||||
advice on how to make it even better.
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- big-rewrite
|
||||
---
|
||||
|
||||
# Don’t Look Into the Light
|
||||
|
||||
So at a previous job I was working at, we maintained a system. This system
|
||||
powered a significant part of the core of how the product was actually used (as
|
||||
far as usage metrics reported). Over time, we had bolted something onto the side
|
||||
|
@ -84,7 +82,7 @@ terrible idea. Microservices architectures are not planned. They are an
|
|||
evolutionary result, not a fully anticipated feature.
|
||||
|
||||
Finally, don’t “design for the future”. The future [hasn’t happened
|
||||
yet](https://christine.website/blog/all-there-is-is-now-2019-05-25). Nobody
|
||||
yet](https://xeiaso.net/blog/all-there-is-is-now-2019-05-25). Nobody
|
||||
knows how it’s going to turn out. The future is going to happen, and you can
|
||||
either adapt to it as it happens in the Now or fail to. Don’t make things overly
|
||||
modular, that leads to insane things like dynamically linking parts of an
|
||||
|
|
|
@ -9,8 +9,6 @@ tags:
|
|||
- gitea
|
||||
---
|
||||
|
||||
# Continuous Deployment to Kubernetes with Gitea and Drone
|
||||
|
||||
Recently I put a complete rewrite of [the printerfacts
|
||||
server](https://printerfacts.cetacean.club) into service based on
|
||||
[warp](https://github.com/seanmonstar/warp). I have it set up to automatically
|
||||
|
@ -281,7 +279,7 @@ step.
|
|||
The deploy step does two small things. First, it installs
|
||||
[dhall-yaml](https://github.com/dhall-lang/dhall-haskell/tree/master/dhall-yaml)
|
||||
for generating the Kubernetes manifest (see
|
||||
[here](https://christine.website/blog/dhall-kubernetes-2020-01-25)) and then
|
||||
[here](https://xeiaso.net/blog/dhall-kubernetes-2020-01-25)) and then
|
||||
runs
|
||||
[`scripts/release.sh`](https://tulpa.dev/cadey/printerfacts/src/branch/master/scripts/release.sh):
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
---
|
||||
title: Emoji is not a Language
|
||||
date: 2021-07-14
|
||||
tags:
|
||||
- linguistics
|
||||
- philosophy
|
||||
---
|
||||
|
||||
What is a language? This is something that is surprisingly controversial.
|
||||
There's some easy ways to tell when something is a language (one of them being
|
||||
that they have an army), but what about things like emoji? Is emoji a language?
|
||||
In this article I will attempt to argue that emoji is not a language unto
|
||||
itself.
|
||||
|
||||
At a high level, language is a tool that we use to represent
|
||||
spatial/temporal/conceptual relations between objects/ideas/things, statements
|
||||
about reality and similar things among that nature. Many languages are broken
|
||||
into units of meaning that we call words. Here are some example words:
|
||||
|
||||
- the
|
||||
- taco
|
||||
- is
|
||||
- beautiful
|
||||
|
||||
We can break these words into two basic classes like this:
|
||||
|
||||
| Content | Grammar |
|
||||
| :------- | :------- |
|
||||
| taco | the |
|
||||
| beautiful | is |
|
||||
|
||||
It's worth noting that not all verbs fall into the "grammar" category. Things
|
||||
like "eat" would fall into a content word, however "is" is a special case
|
||||
because it is directly drawing a relation between two things. In the sentence
|
||||
"The taco is beautiful", there is a relation being made from one specific taco
|
||||
and the abstract concept of beauty.
|
||||
|
||||
I want to argue that emoji has plenty of content words, but no grammar words. If
|
||||
we wanted to assemble an analog to "The taco is beautiful" in emoji, we could
|
||||
make 1:1 correlations between English words and emoji like this:
|
||||
|
||||
| English | Emoji |
|
||||
|:------- |:----- |
|
||||
| the | |
|
||||
| taco | 🌮 |
|
||||
| is | |
|
||||
| beautiful | 🎀 |
|
||||
|
||||
I dug through the entire emoji chart and was unable to find things that could be
|
||||
used for "the" and "is". Heck, even the word I used for "beautiful" was a
|
||||
stretch because the ribbon emoji is normally used that way. Is a language
|
||||
defined by words that have inherent meaning or is that meaning arbitrarily
|
||||
assigned by its users? Can I just firng out words like "xnoypt" as in "realizing
|
||||
how the word would be pronounced, Tom [xnoypted](https://youtu.be/aMgCBYgVwsI)
|
||||
out of existence"? Does that mean "xnoypt" is a word?
|
||||
|
||||
The closest I was able to get to "the" and "is" would be metaphors that would
|
||||
fall apart when you want to discuss the actual things involved. Let's say that
|
||||
you assign arbitrary emoji at least to "is" so that you can end up with this
|
||||
sentence in emoji:
|
||||
|
||||
🌮➡️🎀
|
||||
|
||||
What if you want to talk about the concept of right though? Say you want to
|
||||
convey that the taco store is to the right of the office building. You'd need to
|
||||
say something like:
|
||||
|
||||
🌮🏪➡️➡️🏢
|
||||
|
||||
And this could be easily confused with the interpretation "taco store right
|
||||
right office building".
|
||||
|
||||
But how do you know that it's a taco store? That's just a convention English
|
||||
follows where the thing being described is the right-most thing and other things
|
||||
on the left are just qualifiers or determiners to what's going on about it. It's
|
||||
a "taco store", not a "store taco". Other languages like French do have this
|
||||
reversed, so it could easily become a source of confusion.
|
||||
|
||||
So what if you ripped out the grammar entirely? What if you just had something
|
||||
that was pure content? Could utterances like "🌮🏪➡️🏢" function in place of
|
||||
something that breaks apart the words into groups? How would people know the
|
||||
difference between that being a giant list of descriptors on top of a taco or an
|
||||
office building?
|
||||
|
||||
How would you express verbs like "to eat"? Emojipedia says that 🍴 is used to
|
||||
signify eating, but what about cultures that don't use cutlery to eat with?
|
||||
Would this really be global enough to work in places like China? Cultural
|
||||
cross-contamination would likely be enough at this point that most people could
|
||||
get the message, but is this really representing the idea of eating or the idea
|
||||
of something that you can use to eat other things? Would using this mean that
|
||||
you could express what you ate with emoji? What would make it more of a concept
|
||||
of eating than "to eat", "mangxi" (Esperanto), "manger" (French), or "citka"
|
||||
(Lojban)?
|
||||
|
||||
If language is a tool that we can use to describe relations, then we can sorta
|
||||
get them across with emoji by piggy-backing on top of the grammar of other
|
||||
languages. You can derive new words like "taco store" with phrases like "🌮🏪".
|
||||
You can use these to create meaning, I guess, but it wouldn't be very precise.
|
||||
You could get across the most common words and cultural ideas, but not much
|
||||
else.
|
||||
|
||||
Certainly not technical things where detail is important. Where is that taco
|
||||
store in relation to the office building? Is it 5 meters to the right of it or
|
||||
500 meters? What color is the office building? What name does it have? What is
|
||||
the name of the road? What is the name of the taco store?
|
||||
|
||||
What can you really convey with emoji that isn't also conveyed with words?
|
||||
|
||||
You can create new words easily with some chat platforms and how they use emoji
|
||||
though. You can either describe "nonbinary people" as "🚫🔢0️1️🧍" or you can just
|
||||
upload an image of the [nonbinary pride
|
||||
flag](https://gender.wikia.org/wiki/Pride_Flags#Nonbinary_Flag) to use as a
|
||||
direct descriptor of the concept instead. In a way emoji gives you a level of
|
||||
freedom of expression that simple words can't. The word "xnoypt" makes sense to
|
||||
people that know the word, but the picture has a greater chance of being closer
|
||||
to understood on its own. Here is an emoji that my coworkers use as a loving
|
||||
description:
|
||||
|
||||
<center>
|
||||
|
||||
![](https://cdn.christine.website/file/christine-static/blog/friday_deploy.png)
|
||||
|
||||
</center>
|
||||
|
||||
This one is called `friday_deploy` and is used as the avatar of our deployment
|
||||
bot as well as a way to describe the abstract horror of deploying software on a
|
||||
Friday. By being an emoji it can represent something more than just the
|
||||
pictograph that it is.
|
||||
|
||||
These all certainly encode meaning on their own, but meaning on its own doesn't
|
||||
make a language. Emoji certainly could become a language, but it would need a
|
||||
lot of work to become one. Even then it would likely fall into the other
|
||||
failings that International Auxiliary Languages that have fell into. It is
|
||||
easier to type emoji than it is to type things like Esperanto's "ĉ", but it's
|
||||
going to inherently encode assumptions in the creator's first language.
|
||||
|
||||
Emoji is not a language, it's used to augment existing languages.
|
||||
|
||||
> If you want to claim that emoji is a language, you should be able to make that
|
||||
> same claim using emoji. Not an ad hoc cypher of the english sentence; just use
|
||||
> emoji the way people commonly use them, which you're saying counts as a
|
||||
> language, to say "Emoji is a language".
|
||||
|
||||
- allthingslinguistic
|
||||
|
||||
I'd be willing to be proven wrong if you can write "Emoji is a language"
|
||||
unambiguously using emoji without it being a baroque cipher of English.
|
|
@ -6,8 +6,6 @@ tags:
|
|||
series: freenode
|
||||
---
|
||||
|
||||
# Epilogue
|
||||
|
||||
The last caretaker's absence rippled throughout the halls. The darkness was all
|
||||
that remained.
|
||||
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
---
|
||||
title: "Things I'm Excited for in 2022"
|
||||
date: 2021-12-28
|
||||
author: ectamorphic
|
||||
---
|
||||
|
||||
2021 has been...a thing. However there are a lot of things that I am looking
|
||||
forward to in 2022 that I'm gonna summarize in a few categories.
|
||||
|
||||
## VR
|
||||
|
||||
2021 has been a really dry year for VR tech. The chip shortage has really hurt
|
||||
the budding VR industry, but there are some things that have been announced that
|
||||
I am looking forward to.
|
||||
|
||||
[VR has really been one of the main things that's been keeping me sane over the
|
||||
eternal plague. It's become one of my main activities and I am looking forward
|
||||
to the improvements that come with new generations of VR
|
||||
tech.](conversation://Cadey/enby)
|
||||
|
||||
### Simula One
|
||||
|
||||
[Simula](https://simulavr.com/) is trying to create a VR headset that can
|
||||
function as a monitor replacement. This is something I am _really_ excited for.
|
||||
The Simula One has a lot of potential to change how people use computers.
|
||||
|
||||
Right now a lot of the "working in VR" kinds of projects try to recreate the
|
||||
_experience_ of using a desktop PC in VR. This makes sense, the existing
|
||||
paridigm is already there and people are already familiar with it. However there
|
||||
is also a lot of room for ditching the constraints of the past and really
|
||||
experimenting with what computing can be if you aren't constrained by monitors.
|
||||
|
||||
The Simula One headset is going to have [one of the highest pixels-per-degree on
|
||||
the market for consumer VR](https://simulavr.com/blog/vr-comparison/). It's
|
||||
going to be running NixOS and [Monado](https://monado.freedesktop.org/).
|
||||
|
||||
I don't really know if it is going to take off and if the result will be any
|
||||
good, however it's very important that people try these kinds of things. Who
|
||||
knows what will catch on? They are going to open up a kickstarter in January and
|
||||
I plan to be one of the early high tier donators.
|
||||
|
||||
### Valve "deckard"
|
||||
|
||||
Valve has been working on the Steam Deck, but there's also a section of Valve
|
||||
that has been hard at work on a VR headset codenamed
|
||||
["deckard"](https://www.theverge.com/2021/9/29/22699914/valve-deckard-standalone-vr-headset-prototype-development).
|
||||
The rumor mill says it will have an option to run as a standalone headset as
|
||||
well as a traditional PCVR headset. Other digging into things have found a wifi
|
||||
chip (a specific wifi6 realtek one) that would allow for streaming VR gameplay
|
||||
over a network and there are also references to using
|
||||
[xrdesktop](https://www.collabora.com/news-and-blog/news-and-events/moving-the-linux-desktop-to-another-reality.html)
|
||||
as a way to run "flat" applications in a VR space. There are also rumors that it
|
||||
will support "inside-out" tracking, which is also essential for being a portable
|
||||
headset.
|
||||
|
||||
I would absolutely love to have such a thing. I travel occasionally for work and
|
||||
I would really love to have a quality PCVR experience on the go. It would let me
|
||||
be able to not skip my workout days when I'm in a hotel room.
|
||||
|
||||
The VR space on Linux is slightly stagnated at the moment due to most of the
|
||||
investment either being in SteamVR on Windows or on Oculus' fork of Android.
|
||||
This does make sense though, there is a lot of money to be made in the VR space.
|
||||
|
||||
Hopefully Valve can improve the state of VR on Linux with the "deckard".
|
||||
|
||||
## Video Games
|
||||
|
||||
2021 has had some banger releases. Halo Infinite finally dropped. Final Fantasy
|
||||
7 Remake came to PC. [Metroid
|
||||
Dread](https://xeiaso.net/blog/metroid-dread-review-2021-10-10) finally
|
||||
came out after being rumored for more than half of my lifetime. Forza Horizon 5
|
||||
raced out into the hearts of millions. Overall, it was a pretty good year to be
|
||||
a gamer.
|
||||
|
||||
[I was going to do a writeup of my thoughts on Halo Infinite, however I really
|
||||
want to reserve that for when I can do it co-op. From what I've heard of the
|
||||
development of Infinite there were many points where they didn't think that the
|
||||
game would ship at all. It came out though. It's decent, movement is really fun,
|
||||
but overall I don't feel it's going to be genre-defining in the ways they would
|
||||
have hoped.](conversation://Cadey/coffee)
|
||||
|
||||
However 2022 looks like we're going to finally start returning to "normal" with
|
||||
development schedules. Here's what I'm the most excited for:
|
||||
|
||||
### Steam Deck
|
||||
|
||||
The [Steam Deck](https://www.steamdeck.com/en/) is a handheld PC that will let
|
||||
you play games. It's also likely going to be my first "next gen" console, as
|
||||
despite my repeated attempts I have been unable to get an Xbox Series console or
|
||||
a PS5.
|
||||
|
||||
[Is the Steam Deck really a console? It's much more like a PC, but it's not as
|
||||
much of a console as the Oculus Quest 2 is.](conversation://Mara/hmm)
|
||||
|
||||
[Let's just call it a console for the sake of
|
||||
argument.](conversation://Cadey/coffee)
|
||||
|
||||
I'm excited for this on multiple levels. Valve is going to make it run SteamOS 3
|
||||
by default. SteamOS is based on Arch Linux and they have been making improvement
|
||||
after improvement to the Linux kernel and all of the software they are going to
|
||||
use on it. Valve hopes to have most games on Steam playable like they are on a
|
||||
PC running windows.
|
||||
|
||||
It's also a bit of a chunky boi. It's gonna be a bit hefty, but I'm excited for
|
||||
what it is going to bring to the ecosystem. It may lead to the year of Linux on
|
||||
the desktop!
|
||||
|
||||
[Isn't that every year though?](conversation://Mara/hmm)
|
||||
|
||||
### Splatoon 3
|
||||
|
||||
Splatoon is one of my favorite game series. It's a game where you have a bunch
|
||||
of ink guns and your goal is to cover as much turf as possible. The game feels
|
||||
like Quake in the best ways. You use your sticks to lead and the gyroscope to
|
||||
refine your aim, just like you would with a Steam Controller.
|
||||
|
||||
[I'm still sad that the Steam Controller failed in the
|
||||
market.](conversation://Cadey/coffee)
|
||||
|
||||
Splatoon 3 looks like it will build on the fundamentals in great ways. I can't
|
||||
wait to see what they have in store!
|
||||
|
||||
### The Sequel to The Legend of Zelda: Breath of The Wild
|
||||
|
||||
I have over 400 hours logged in Breath of The Wild. It is in the running for my
|
||||
favorite games of all time. The really innovative part of Breath of The Wild was
|
||||
the fact that it was a jRPG without a leveling mechanic, experience points or a
|
||||
hard-defined story path. You are dumped into the world, given tools to explore
|
||||
through it and then given free reign to do whatever you want. It is a massive
|
||||
open world (probably one of the biggest in a Nintendo game save maybe Xenoblade
|
||||
Chronicles X) and you are given the agency you need to play the game how you
|
||||
want. You can run straight to Ganon and finish the game in less than an hour.
|
||||
You can spend hundreds of hours exploring the world to solve all the puzzle
|
||||
shrines.
|
||||
|
||||
Most of all though, the really great part about Breath of The Wild is the fact
|
||||
that as you play, your skill as a player improves. You learn to chain together
|
||||
mechanics to do basically whatever you want and the game doesn't stop you. You
|
||||
can do _whatever you want_ and the real progression system is your skill.
|
||||
|
||||
[This sounds weird, but tying progression to player skill is incredibly
|
||||
anti-meta as far as these games go. Usually jRPGs are very tailored experiences
|
||||
where you go through the standard "fetch bread -> kill god" kind of power skill
|
||||
tree, but with Breath of The Wild you can "kill god" right out of the gate and
|
||||
"fetch bread" later.](conversation://Cadey/enby)
|
||||
|
||||
I have no idea what to expect for the sequel to Breath of The Wild, but I'm
|
||||
excited as heck to see what they come up with.
|
||||
|
||||
[This is going to have an article written about it once I've gotten a chance to
|
||||
play through it. This may take a week to a month. It's gonna be worth the
|
||||
wait.](conversation://Cadey/enby)
|
||||
|
||||
## My Projects
|
||||
|
||||
I don't really like having too many project plans ahead of time, but here are
|
||||
the biggest things I'm already committing myself to do next year. Something
|
||||
something forward looking statements something something.
|
||||
|
||||
### Daily Workout Streams
|
||||
|
||||
I love rhythm games. I haven't really had good rhythm games to play until I got
|
||||
back into VR. I've been playing a lot of [Beat
|
||||
Saber](https://store.steampowered.com/app/620980/Beat_Saber/) and more recently
|
||||
[Synth Riders](https://synthridersvr.com/). I've been streaming my play on
|
||||
[Twitch](https://twitch.tv/princessxen) and I have a playlist of the VODs on
|
||||
[YouTube](https://www.youtube.com/playlist?list=PLJDDsMrk2tSH3nhLWqV8IZLgae1CNYurH).
|
||||
|
||||
I live a very sedentary lifestyle, even before COVID, and I want to start to get
|
||||
back into shape. Doing it [dancing on the
|
||||
internet](https://youtu.be/q3F06mKP2uk?list=PLJDDsMrk2tSH3nhLWqV8IZLgae1CNYurH&t=4342)
|
||||
is fun, so why not?
|
||||
|
||||
### Spellblade
|
||||
|
||||
I have a bunch of unreleased material for Spellblade that I need to go in and
|
||||
edit up and post.
|
||||
|
||||
### V-Tubing
|
||||
|
||||
I got a webcam for Christmas that I plan to use for V-Tubing coming soon. I want
|
||||
to use it for recording conference talks as well as for doing some non-VR gaming
|
||||
streams.
|
||||
|
||||
I have been working on getting a V-Tuber model hacked up out of the one that
|
||||
I've been using in VRChat, but having no idea what I am doing in Unity has
|
||||
really not been helping.
|
||||
|
||||
---
|
||||
|
||||
Hope this was an interesting view into what I'm excited for. This may be my last
|
||||
post for the year. Stay safe out there, things have been rough.
|
|
@ -3,8 +3,6 @@ title: I Put Words on this Webpage so You Have to Listen to Me Now
|
|||
date: 2018-11-30
|
||||
---
|
||||
|
||||
# I Put Words on this Webpage so You Have to Listen to Me Now
|
||||
|
||||
Holy cow. I am angry at how people do thing with tool. People do thing with tool so badly. You shouldn't do thing with tool, you should do other thing, compare this:
|
||||
|
||||
I am using tool. I want to do thing. I flopnax the ropjar and then I get the result of doing thing (because it's convenient to flopnax the ropjar given the existing program structure).
|
||||
|
|
|
@ -8,8 +8,6 @@ tags:
|
|||
- heroku
|
||||
---
|
||||
|
||||
# Farewell Email - Heroku
|
||||
|
||||
## May our paths cross again
|
||||
|
||||
Hey all,
|
||||
|
@ -20,7 +18,7 @@ The people I've worked with at Heroku have been catalytic to our success as a le
|
|||
|
||||
There is no doubt in my mind that you all will build fantastically useful and stable tools for Salesforce customers. Keep your eyes on what matters, let your heart guide your actions, and you all will continue to construct and refine the finest possible infrastructure that is possible. We may be limited as humans, but together in groups like this we can surpass these arbitrary differences and create things that really shine.
|
||||
|
||||

> As one being we repeat the words:

|
||||
> As one being we repeat the words:
|
||||
>
|
||||
> Flow in compassion
|
||||
> Release what is divine
|
||||
|
|
|
@ -6,8 +6,6 @@ for: Twilight Sparkle
|
|||
series: stories
|
||||
---
|
||||
|
||||
# Fear
|
||||
|
||||
_I must not fear._
|
||||
_Fear is the mind-killer._
|
||||
_Fear is the little-death that brings total obliteration._
|
||||
|
|
|
@ -5,8 +5,6 @@ tags:
|
|||
- gemini
|
||||
---
|
||||
|
||||
# RSS/Atom Feeds Fixed and Announcing my Flight Journal
|
||||
|
||||
I have released version 2.0.1 of this site's code. With it I have fixed the RSS
|
||||
and Atom feed generation. For now I have had to sacrifice the post content being
|
||||
in the feed, but I will bring it back as soon as possible.
|
||||
|
|
|
@ -7,9 +7,6 @@ tags:
|
|||
- nim
|
||||
---
|
||||
|
||||
FFI-ing Golang from Nim for Fun and Profit
|
||||
==========================================
|
||||
|
||||
As a side effect of Go 1.5, the compiler and runtime recently gained the
|
||||
ability to compile code and run it as FFI code running in a C namespace. This
|
||||
means that you can take any Go function that expresses its types and the like
|
||||
|
|
|
@ -6,8 +6,6 @@ tags:
|
|||
series: freenode
|
||||
---
|
||||
|
||||
# Final Chapter
|
||||
|
||||
The last caretaker looked at the last light lit in the empty halls. They looked
|
||||
out across their home. It used to be filled with thousands of people. There were
|
||||
discussions about every topic imaginable from people of as many backgrounds.
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
title: "Fly.io: the Reclaimer of Heroku's Magic"
|
||||
date: 2022-05-15
|
||||
tags:
|
||||
- flyio
|
||||
- heroku
|
||||
vod:
|
||||
twitch: https://www.twitch.tv/videos/1484123245
|
||||
youtube: https://youtu.be/BAgzkKpLVt4
|
||||
---
|
||||
|
||||
Heroku was catalytic to my career. It's been hard to watch the fall from grace.
|
||||
Don't get me wrong, Heroku still _works_, but it's obviously been in maintenance
|
||||
mode for years. When I worked there, there was a goal that just kind of grew in
|
||||
scope over and over without reaching an end state: the Dogwood stack.
|
||||
|
||||
In Heroku each "stack" is the substrate the dynos run on. It encompasses the AWS
|
||||
runtime, the HTTP router, the logging pipeline and a bunch of the other
|
||||
infrastructure like the slug builder and the deployment infrastructure. The
|
||||
three stacks Heroku has used are named after trees: Aspen, Bamboo and Cedar.
|
||||
Every Heroku app today runs on the Cedar stack, and compared to Bamboo it was a
|
||||
generational leap in capability. Cedar was what introduced buildpacks and
|
||||
support for any language under the sun. Prior stacks railroaded you into Ruby on
|
||||
Rails (Heroku used to be a web IDE for making Rails apps). However there were
|
||||
always plans to improve with another generational leap. This ended up being
|
||||
called the "Dogwood stack", but Dogwood never totally materialized because it
|
||||
was too ambitious for Heroku to handle post-acquisition. Parts of Dogwood's
|
||||
roadmap ended up being used in the implementation of Private Spaces, but as a
|
||||
whole I don't expect Dogwood to materialize in Heroku in the way we all had
|
||||
hoped.
|
||||
|
||||
However, I can confidently say that [fly.io](https://fly.io) seems like a viable
|
||||
inheritor of the mantle of responsibility that Heroku has left into the hands of
|
||||
the cloud. fly.io is a Platform-as-a-Service that hosts your applications on top
|
||||
of physical dedicated servers run all over the world instead of being a reseller
|
||||
of AWS. This allows them to get your app running in multiple regions for a lot
|
||||
less than it would cost to run it on Heroku. They also use anycasting to allow
|
||||
your app to use the same IP address globally. The internet itself will load
|
||||
balance users to the nearest instance using BGP as the load balancing
|
||||
substrate.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="enby">People have been asking me what I would
|
||||
suggest using instead of Heroku. I have been unable to give a good option until
|
||||
now. If you are dissatisfied with the neglect of Heroku in the wake of the
|
||||
Salesforce acquisition, take a look at fly.io. Its free tier is super generous.
|
||||
I worked at Heroku and I am beyond satisfied with it. I'm considering using it
|
||||
for hosting some personal services that don't need something like
|
||||
NixOS.</xeblog-conv>
|
||||
|
||||
Applications can be built either using [cloud native
|
||||
buildpacks](https://fly.io/docs/reference/builders/), Dockerfiles or arbitrary
|
||||
docker images that you generated with something like Nix's
|
||||
`pkgs.dockerTools.buildLayeredImage`. This gives you freedom to do whatever you
|
||||
want like the Cedar stack, but at a fraction of the cost. Its default instance
|
||||
size is likely good enough to run the blog you are reading right now and would
|
||||
be able to do that for $2 a month plus bandwidth costs (I'd probably estimate
|
||||
that to be about $3-5, depending on how many times I get on the front page of
|
||||
Hacker News).
|
||||
|
||||
You can have persistent storage in the form of volumes, poke the internal DNS
|
||||
server fly.io uses for service discovery, run apps that use arbitrary TCP/UDP
|
||||
ports (even a DNS server!), connect to your internal network over WireGuard, ssh
|
||||
into your containers, and import Heroku apps into fly.io without having to
|
||||
rebuild them. This is what the Dogwood stack should have been. This represents a
|
||||
generational leap in the capabilities of what a Platform as a Service can do.
|
||||
|
||||
The stream VOD in the footer of this post contains my first impressions using
|
||||
fly.io to try and deploy an app written with [Deno](https://deno.land) to the
|
||||
cloud. I ended up creating a terrible CRUD app on stream using SQLite that
|
||||
worked perfectly beyond expectations. I was able to _restart the app_ and my
|
||||
SQLite database didn't get blown away. I could easily imagine myself combining
|
||||
something like [litestream](https://litestream.io) into my docker images to
|
||||
automate offsite backups of SQLite databases like this. It was magical.
|
||||
|
||||
<xeblog-conv name="Mara" mood="happy">If you've never really used Heroku, for
|
||||
context each dyno has a mutable filesystem. However that filesystem gets blown
|
||||
away every time a dyno reboots. Having something that is mutable and persistent
|
||||
is mind-blowing.</xeblog-conv>
|
||||
|
||||
Everything else you expect out of Heroku works like you'd expect in fly.io. The
|
||||
only things I can see missing are automated Redis hosting by the platform
|
||||
(however this seems intentional as fly.io is generic enough [to just run redis
|
||||
directly for you](https://fly.io/docs/reference/redis/)) and the marketplace.
|
||||
The marketplace being absent is super reasonable, seeing as Heroku's marketplace
|
||||
only really started existing as a result of them being the main game in town
|
||||
with all the mindshare. fly.io is a voice among a chorus, so it's understandable
|
||||
that it wouldn't have the same treatment.
|
||||
|
||||
Overall, I would rate fly.io as a worthy inheritor of Heroku's mantle as the
|
||||
platform as a service that is just _magic_. It Just Works™️. There was no
|
||||
fighting it at a platform level, it just worked. Give it a try.
|
||||
|
||||
<xeblog-conv name="Cadey" mood="enby">Don't worry
|
||||
[@tqbf](https://twitter.com/tqbf), fly.io put in a good showing. I still wanna
|
||||
meet you at some conference.</xeblog-conv>
|
|
@ -6,8 +6,6 @@ tags:
|
|||
series: freenode
|
||||
---
|
||||
|
||||
# Footnote
|
||||
|
||||
- [Final Chapter](/blog/final-chapter-2021-05-20)
|
||||
- [Epilogue](/blog/epilogue-2021-05-26)
|
||||
|
||||
|
|
|
@ -4,13 +4,11 @@ date: 2019-05-19
|
|||
series: conlangs
|
||||
---
|
||||
|
||||
# A Formal Grammar of `h`
|
||||
|
||||
## Introduction
|
||||
|
||||
`h` is a conlang project that I have been working off and on for years. It is infinitely simply teachable, trivial to master and can be used to represent the entire scope of all meaning in any facet of the word. All with a single character.
|
||||
|
||||
This is a continuation from [this post](https://christine.website/blog/the-origin-of-h-2015-12-14). If this post makes sense to you, please let me know and/or schedule a psychologist appointment just to be safe.
|
||||
This is a continuation from [this post](https://xeiaso.net/blog/the-origin-of-h-2015-12-14). If this post makes sense to you, please let me know and/or schedule a psychologist appointment just to be safe.
|
||||
|
||||
## Phonology
|
||||
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
---
|
||||
title: Fun with Redirection
|
||||
date: 2021-09-22
|
||||
author: Twi
|
||||
tags:
|
||||
- shell
|
||||
- redirection
|
||||
- osdev
|
||||
---
|
||||
|
||||
When you're hacking in the shell or in a script, sometimes you want to change
|
||||
how the output of a command is routed. Today I'm gonna cover common shell
|
||||
redirection tips and tricks that I use every day at work and how it all works
|
||||
under the hood.
|
||||
|
||||
Let's say you're trying to capture the output of a command to a file, such as
|
||||
`uname -av`:
|
||||
|
||||
```console
|
||||
$ uname -av
|
||||
Linux shachi 5.13.15 #1-NixOS SMP Wed Sep 8 06:50:21 UTC 2021 x86_64 GNU/Linux
|
||||
```
|
||||
|
||||
You could copy that to the clipboard and paste it into a file, but there is a
|
||||
better way thanks to the `>` operator:
|
||||
|
||||
```console
|
||||
$ uname -av > uname.txt
|
||||
$ cat uname.txt
|
||||
Linux shachi 5.13.15 #1-NixOS SMP Wed Sep 8 06:50:21 UTC 2021 x86_64 GNU/Linux
|
||||
```
|
||||
|
||||
Let's say you want to run this on a few machines and put all of the output into
|
||||
`uname.txt`. You could write a shell script loop like this:
|
||||
|
||||
```sh
|
||||
# make sure the file doesn't already exist
|
||||
rm -f uname.txt
|
||||
|
||||
for host in shachi chrysalis kos-mos ontos pneuma
|
||||
do
|
||||
ssh $host -- uname -av >> uname.txt
|
||||
done
|
||||
```
|
||||
|
||||
Then `uname.txt` should look like this:
|
||||
|
||||
```
|
||||
Linux shachi 5.13.15 #1-NixOS SMP Wed Sep 8 06:50:21 UTC 2021 x86_64 GNU/Linux
|
||||
Linux chrysalis 5.10.63 #1-NixOS SMP Wed Sep 8 06:49:02 UTC 2021 x86_64 GNU/Linux
|
||||
Linux kos-mos 5.10.45 #1-NixOS SMP Fri Jun 18 08:00:06 UTC 2021 x86_64 GNU/Linux
|
||||
Linux ontos 5.10.52 #1-NixOS SMP Tue Jul 20 14:05:59 UTC 2021 x86_64 GNU/Linux
|
||||
Linux pneuma 5.10.57 #1-NixOS SMP Sun Aug 8 07:05:24 UTC 2021 x86_64 GNU/Linux
|
||||
```
|
||||
|
||||
Now let's say you want to extract all of the hostnames from that `uname.txt`.
|
||||
The pattern of the file seems to specify that fields are separated by spaces and
|
||||
the hostname seems to be the second space-separated field in each line. You can
|
||||
use the `cut` command to select that small subset from each line, and you can
|
||||
feed the `cut` command's standard input using the `<` operator:
|
||||
|
||||
```console
|
||||
$ cut -d ' ' -f 2 < uname.txt
|
||||
shachi
|
||||
chrysalis
|
||||
kos-mos
|
||||
ontos
|
||||
pneuma
|
||||
```
|
||||
|
||||
[It's worth noting that a lot of these core CLI utilities are built on the idea
|
||||
that they are _filters_, or things that take one infinite stream of text in on
|
||||
one end and then return another stream of text out the other
|
||||
end. This is done through a channel called "standard input/output", where
|
||||
standard input refers to input to the command and standard output refers to the
|
||||
output of the command.](conversation://Mara/hacker)
|
||||
|
||||
[That's a great metaphor, let's build onto it using the `|` (pipe)
|
||||
operator. The pipe operator lets you pipe the standard output of one command to
|
||||
the standard input of another.](conversation://Cadey/enby)
|
||||
|
||||
[You mentioned that you can pass files as input and output for commands, does
|
||||
this mean that standard input and standard output are
|
||||
files?](conversation://Mara/happy)
|
||||
|
||||
[Precisely! They are just files that are automatically open for every process.
|
||||
Usually commands will output to standard out and some will also accept input via
|
||||
standard in.](conversation://Cadey/enby)
|
||||
|
||||
[Doesn't that have some level of overhead though? Isn't it expensive to spin up
|
||||
a whole heckin' `cat` process for that?](conversation://Mara/hmm)
|
||||
|
||||
[Not on any decent system made in the last 20 years. This may have some impact
|
||||
on Windows (because they have core architectural mistakes that make processes
|
||||
take up to 100 milliseconds to spin up), but this is about Unix/Linux. I think
|
||||
these should work on Windows too if you use Cygwin, but if you're using WSL you
|
||||
shouldn't have any real issues there](conversation://Cadey/coffee)
|
||||
|
||||
Let's say we want to rewrite that `cut` command above to use pipes. You could
|
||||
write it like this:
|
||||
|
||||
```sh
|
||||
cat uname.txt | cut -d ' ' -f 2
|
||||
```
|
||||
|
||||
[The mnemonic we use for remembering the `cut` command is that fields are
|
||||
separated by the `d`elimiter and you cut out the nth
|
||||
`f`ield/s.](conversation://Mara/hacker)
|
||||
|
||||
This will get you the exact same output:
|
||||
|
||||
```console
|
||||
$ cat uname.txt | cut -d ' ' -f 2
|
||||
shachi
|
||||
chrysalis
|
||||
kos-mos
|
||||
ontos
|
||||
pneuma
|
||||
```
|
||||
|
||||
Personally I prefer writing shell pipelines like that as it makes it a bit
|
||||
easier to tack on more specific selectors or operations as you go along. For
|
||||
example, if you wanted to sort them you could pipe the result to `sort`:
|
||||
|
||||
```console
|
||||
$ cat uname.txt | cut -d ' ' -f 2 | sort
|
||||
chrysalis
|
||||
kos-mos
|
||||
ontos
|
||||
pneuma
|
||||
shachi
|
||||
```
|
||||
|
||||
This lets you gradually build up a shell pipeline as you drill down to the data
|
||||
you want in the format you want.
|
||||
|
||||
[I wanted to save this compiler error to a file but it didn't work. I tried
|
||||
doing this:](conversation://Mara/hmm)
|
||||
|
||||
```console
|
||||
$ rustc foo.rs > foo.log
|
||||
```
|
||||
|
||||
But the output printed to the screen instead of the file:
|
||||
|
||||
```console
|
||||
$ rustc foo.rs > foo.log
|
||||
error: expected one of `!` or `::`, found `main`
|
||||
--> foo.rs:1:5
|
||||
|
|
||||
1 | fun main() {}
|
||||
| ^^^^ expected one of `!` or `::`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
$ cat foo.log
|
||||
$
|
||||
```
|
||||
|
||||
This happens because there are actually _two_ output streams per program. There
|
||||
is the standard out stream and there is also a standard error stream. The reason
|
||||
that standard error exists is so that you can see if any errors have happened if
|
||||
you redirect standard out.
|
||||
|
||||
Sometimes standard out may not be a stream of text, say you have a compressed
|
||||
file you want to analyze and there's an issue with the decompression. If the
|
||||
decompressor wrote its errors to the standard output stream, it could confuse or
|
||||
corrupt your analysis.
|
||||
|
||||
However, we can redirect standard error in particular by modifying how we
|
||||
redirect to the file:
|
||||
|
||||
```console
|
||||
$ rustc foo.rs 2> foo.log
|
||||
$ cat foo.log
|
||||
error: expected one of `!` or `::`, found `main`
|
||||
--> foo.rs:1:5
|
||||
|
|
||||
1 | fun main() {}
|
||||
| ^^^^ expected one of `!` or `::`
|
||||
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
[Where did the `2` come from?](conversation://Mara/wat)
|
||||
|
||||
So I mentioned earlier that redirection modifies the standard input and output
|
||||
of programs. This is not entirely true, but it was a convenient half-truth to
|
||||
help build this part of the explanation.
|
||||
|
||||
For every process on a Unix-like system (such as Linux and macOS), the kernel
|
||||
stores a list of active file-like objects. This includes real files on the
|
||||
filesystem, pipes between processes, network sockets, and more. When a program
|
||||
reads or writes a file, they tell the kernel which file they want to use by
|
||||
giving it a number index into that list, starting at zero. Standard in/out/error
|
||||
are just the conventional names for the first three open files in the list, like
|
||||
this:
|
||||
|
||||
| File Descriptor | Purpose |
|
||||
| :------ | :------- |
|
||||
| 0 | Standard input |
|
||||
| 1 | Standard output |
|
||||
| 2 | Standard error |
|
||||
|
||||
Shell redirection simply changes which files are in that list of open files when
|
||||
the program starts running.
|
||||
|
||||
That is why you use a `2` there, because you are telling the shell to change
|
||||
file descriptor number `2` of the `rustc` process to point to the filesystem
|
||||
file `foo.log`, which in turn makes the standard error of `rustc` get written to
|
||||
that file for you.
|
||||
|
||||
In turn, this also means that `cat foo.txt > foo2.txt` is actually a shortcut
|
||||
for saying `cat foo.txt 1> foo2.txt`, but the `1` can be omitted there because
|
||||
standard out is usually the "default" output that most of these kind of
|
||||
pipelines cares about.
|
||||
|
||||
[How would I get both standard output and standard error in the same
|
||||
file?](conversation://Mara/hmm)
|
||||
|
||||
The cool part about the `>` operator is that it doesn't just stop with output to
|
||||
files on the desk, you can actually have one file descriptor get pointed to
|
||||
another. Let's say you have a need for both standard out and standard error to
|
||||
go to the same file. You can do this with a command like this:
|
||||
|
||||
```
|
||||
$ rustc foo.rs > foo.log 2>&1
|
||||
```
|
||||
|
||||
This tells the shell to point standard out to `foo.log`, and then standard
|
||||
error to standard out (which is now `foo.log`). There's a footgun here though;
|
||||
the order of the redirects matters. Consider the following:
|
||||
|
||||
```
|
||||
$ rustc foo.rs 2>&1 > foo.log
|
||||
error: expected one of `!` or `::`, found `main`
|
||||
--> foo.rs:1:5
|
||||
|
|
||||
1 | fun main() {}
|
||||
| ^^^^ expected one of `!` or `::`
|
||||
|
||||
error: aborting due to previous error
|
||||
$ cat foo.log
|
||||
$ # foo.log is empty, why???
|
||||
```
|
||||
|
||||
We wanted to redirect stderr to `foo.log`, but that didn't happen. Why? Well,
|
||||
the shell considers our redirects one at a time from left to right. When the
|
||||
shell sees `2>&1`, it hasn't considered `> foo.log` yet, so standard out (`1`)
|
||||
is still our terminal. It dutifully redirects stderr to the terminal, which is
|
||||
where it was already going anyway. Then it sees `1 > foo.log`, so it redirects
|
||||
standard out to `foo.log`. That's the end of it though. It doesn't
|
||||
retroactively redirect standard error to match the new standard out, so our
|
||||
errors get dumped to our terminal instead of the file.
|
||||
|
||||
Confusing right? Lucky for us, there's a short form that redirects both at the
|
||||
same time, making this mistake impossible:
|
||||
|
||||
```
|
||||
$ rustc foo.rs &> foo.log
|
||||
```
|
||||
|
||||
This will put standard out and standard error to `foo.log` the same way that
|
||||
`> foo.log 2>&1` will.
|
||||
|
||||
[Will that work in every shell?](conversation://Mara/hmm)
|
||||
|
||||
[It's a bourne shell (`bash`) extension, but I've tested it in `zsh` and `fish`.
|
||||
You can also do `&|` to pipe both standard out and standard error at the same
|
||||
time in the same way you'd do `2>&1 | whatever`.](conversation://Cadey/enby)
|
||||
|
||||
You can also use this with `>>`:
|
||||
|
||||
```
|
||||
$ rustc foo.rs &>> foo.log
|
||||
$ cat foo.log
|
||||
error: expected one of `!` or `::`, found `main`
|
||||
--> foo.rs:1:5
|
||||
|
|
||||
1 | fun main() {}
|
||||
| ^^^^ expected one of `!` or `::
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
error: expected one of `!` or `::`, found `main`
|
||||
--> foo.rs:1:5
|
||||
|
|
||||
1 | fun main() {}
|
||||
| ^^^^ expected one of `!` or `::`
|
||||
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
[How do I redirect standard in to a file?](conversation://Mara/hmm)
|
||||
|
||||
Well, you don't. Standard in is an input, so you can change where it comes
|
||||
_from_, not where it goes.
|
||||
|
||||
But, maybe you want to make a copy of a program's input and send it somewhere
|
||||
else. There is a way to do _that_ using a command called `tee`. `tee` copies
|
||||
its standard input to standard output, but it also writes a second copy to a
|
||||
file. For example:
|
||||
|
||||
```console
|
||||
$ dmesg | tee dmesg.txt | grep 'msedge'
|
||||
[ 70.585463] traps: msedge[4715] trap invalid opcode ip:5630ddcedc4c sp:7ffd41f67700 error:0 in msedge[5630d8fc2000+952d000]
|
||||
[ 70.702544] traps: msedge[4745] trap invalid opcode ip:5630ddcedc4c sp:7ffd41f67700 error:0 in msedge[5630d8fc2000+952d000]
|
||||
[ 70.806296] traps: msedge[4781] trap invalid opcode ip:5630ddcedc4c sp:7ffd41f67700 error:0 in msedge[5630d8fc2000+952d000]
|
||||
[ 70.918095] traps: msedge[4889] trap invalid opcode ip:5630ddcedc4c sp:7ffd41f67700 error:0 in msedge[5630d8fc2000+952d000]
|
||||
[ 71.031938] traps: msedge[4926] trap invalid opcode ip:5630ddcedc4c sp:7ffd41f67700 error:0 in msedge[5630d8fc2000+952d000]
|
||||
[ 71.138974] traps: msedge[4935] trap invalid opcode ip:5630ddcedc4c sp:7ffd41f67700 error:0 in msedge[5630d8fc2000+952d000]
|
||||
[ 1169.163603] traps: msedge[35719] trap invalid opcode ip:556a93951c4c sp:7ffc533f35c0 error:0 in msedge[556a8ec26000+952d000]
|
||||
[ 1213.301722] traps: msedge[36054] trap invalid opcode ip:55a245960c4c sp:7ffe6d169b40 error:0 in msedge[55a240c35000+952d000]
|
||||
[10963.234459] traps: msedge[104732] trap invalid opcode ip:55fdb864fc4c sp:7ffc996dfee0 error:0 in msedge[55fdb3924000+952d000]
|
||||
```
|
||||
|
||||
This would put the output of the `dmesg` command (read from kernel logs) into
|
||||
`dmesg.txt`, as well as sending it into the grep command. You might want to do
|
||||
this when debugging long command pipelines to see exactly what is going into a
|
||||
program that isn't doing what you expect.
|
||||
|
||||
Redirections also work in scripts too. You can also set "default" redirects for
|
||||
every command in a script using the `exec` command:
|
||||
|
||||
```sh
|
||||
exec > out.log 2> error.log
|
||||
|
||||
ls
|
||||
rustc foo.rs
|
||||
```
|
||||
|
||||
This will have the file listing from `ls` written to `out.log` and any errors
|
||||
from `rustc` written to `error.log`.
|
||||
|
||||
A lot of other shell tricks and fun is built on top of these fundamentals. For
|
||||
example you can take a folder, zip it up and then unzip it over on another
|
||||
machine using a command like this:
|
||||
|
||||
```
|
||||
$ tar cz ./blog | ssh pneuma tar xz -C ~/code/christine.website/blog
|
||||
```
|
||||
|
||||
This will run `tar` to create a compressed copy of the `./blog` folder and then
|
||||
pipe that to tar on another computer to extract that into
|
||||
`~/code/christine.website/blog`. It's just pipes and redirection all the way
|
||||
down! Deep inside `ssh` it's really just piping output of commands back and
|
||||
forth over an encrypted network socket. Connecting to an IRC server is just
|
||||
piping in and out data to the chat server, even more so if you use TLS to
|
||||
connect there. In a way you can model just about everything in Unix with pipes
|
||||
and file descriptors because that is the cornerstone of its design: Everything
|
||||
is a file.
|
||||
|
||||
[This doesn't mean it's literally a file on the disk, it means you can _interact
|
||||
with_ just about everything using the same system interface as you do with
|
||||
files. Even things like hard disks and video cards.](conversation://Mara/hacker)
|
||||
|
||||
Here's a fun thing to do. Using [`curl`](https://curl.se/) to read the contents
|
||||
of a URL and [`jq`](https://stedolan.github.io/jq/) to select out bits from a
|
||||
JSON stream, you can make a script that lets you read the most recent title from
|
||||
my blog's [JSONFeed](/blog.json):
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env bash
|
||||
# xeblog-post.sh
|
||||
|
||||
curl -s https://xeiaso.net/blog.json | jq -r '.items[0] | "\(.title) \(.url)"'
|
||||
```
|
||||
|
||||
At the time of writing this post, here is the output I get from this command:
|
||||
|
||||
```
|
||||
$ ./xeblog-post.sh
|
||||
Anbernic RG280M Review https://xeiaso.net/blog/rg280m-review
|
||||
```
|
||||
|
||||
What else could you do with pipes and redirection? The cloud's the limit!
|
||||
|
||||
---
|
||||
|
||||
Thanks to violet spark, cadence, and AstroSnail for looking over this post and
|
||||
fact-checking as well as helping mend some of the brain dump and awkward
|
||||
wording into more polished sentences.
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- fe21
|
||||
---
|
||||
|
||||
# The Relaxing Surreality of VRChat Furry Conventions
|
||||
|
||||
Author's Note: you may want to view this post in a GUI browser for the best experience.
|
||||
|
||||
It is no secret that I am a furry. The main way that a lot of my friends and I meet up is at conventions. COVID has lead to a year without cons for my friend groups. It's gotten bad enough that in one server the convention coordination channel had its name changed from `#conventions` to `#cancelled`. These conventions are expensive (flight/hotel/badge/the dealer's den), tiring and weirdly recharging all at once.
|
||||
|
|
|
@ -8,8 +8,6 @@ tags:
|
|||
- twitch
|
||||
---
|
||||
|
||||
# Gamebridge: Fitting Square Pegs into Round Holes since 2020
|
||||
|
||||
Recently I did a stream called [Twitch Plays Super Mario 64][tpsm64]. During
|
||||
that stream I both demonstrated and hacked on a tool I'm calling
|
||||
[gamebridge][gamebridge]. Gamebridge is a tool that lets you allow games to
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- gods
|
||||
---
|
||||
|
||||
# The Gears and The Gods
|
||||
|
||||
If there are any gods in computing, they are the authors of compilers. The
|
||||
output of compilers is treated as a Heavenly Decree, sometimes used for many
|
||||
sprints or even years after the output has been last emitted.
|
||||
|
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- web
|
||||
---
|
||||
|
||||
# The Fear Of Missing Out
|
||||
|
||||
Humans have evolved over thousands of years with communities that are small,
|
||||
tight-knit and where it is easy to feel like you know everyone in them. The
|
||||
Internet changes this completely. With the Internet, it's easy to send messages,
|
||||
|
|
|
@ -8,8 +8,6 @@ tags:
|
|||
- draft
|
||||
---
|
||||
|
||||
# Get Going: Hello, World!
|
||||
|
||||
This post is a draft of the first chapter in a book I'm writing to help people learn the
|
||||
[Go][go] programming language. It's aimed at people who understand the high
|
||||
level concepts of programming, but haven't had much practical experience with
|
||||
|
@ -18,7 +16,7 @@ it. This is a sort of spiritual successor to my old
|
|||
ecosystem since then, as well as my understanding of the language.
|
||||
|
||||
[go]: https://golang.org
|
||||
[gswg]: https://christine.website/blog/getting-started-with-go-2015-01-28
|
||||
[gswg]: https://xeiaso.net/blog/getting-started-with-go-2015-01-28
|
||||
|
||||
Like always, feedback is very welcome. Any feedback I get will be used to help
|
||||
make this book even better.
|
||||
|
|
|
@ -4,9 +4,6 @@ date: 2015-01-28
|
|||
series: howto
|
||||
---
|
||||
|
||||
Getting Started with Go
|
||||
=======================
|
||||
|
||||
Go is an exciting language made by Google for systems programming. This article
|
||||
will help you get up and running with the Go compiler tools.
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- release
|
||||
---
|
||||
|
||||
# gitea-release Tool Announcement
|
||||
|
||||
I'm a big fan of automating things that can possibly be automated. One of the
|
||||
biggest pains that I've consistently had is creating/tagging releases of
|
||||
software. This has been a very manual process for me. I have to write up
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
---
|
||||
title: "GNU Doesn't Care About Your Agency"
|
||||
date: 2022-02-10
|
||||
tags:
|
||||
- gnu
|
||||
- libre
|
||||
- rant
|
||||
---
|
||||
|
||||
<div class="warning">
|
||||
|
||||
[EDIT(2022-02-10 12:47 EST): I apparently misread part of the GNU #guix channel
|
||||
rules and made an unreasonable assumption that violators of the rules could be
|
||||
banned. I have amended a conversation fragment accordingly. My intent was not to
|
||||
lie, but to point out that some users actually need stuff that nonguix provides
|
||||
but they just have to know that it exists in the first place.](conversation://Cadey/coffee)
|
||||
|
||||
</div>
|
||||
|
||||
Or: Ubuntu gives the user more agency about how they want to use their computer
|
||||
than fully libre GNU/Linux distros ever can.
|
||||
|
||||
There are many different kinds of Linux distributions, but today we're going to
|
||||
think about a certain kind of distribution: ones where the distribution is
|
||||
totally comprised of free software as much as possible.
|
||||
|
||||
These distributions aim to let users benefit by making it possible to study,
|
||||
hack at and modify every byte of software on the machine's hard drive. This is a
|
||||
fairly noble goal, however in the process of doing this they break core parts of
|
||||
hardware compatibility by "de-blobbing" the kernel. Most of these distributions
|
||||
have a very paternalistic implementation where the "de-blobbed" linux-libre
|
||||
kernel is the _only_ option, thus limiting users' agency.
|
||||
|
||||
For example, let's think about the CPU that I'm using right now. The CPU I'm
|
||||
using is designed to be able to load CPU microcode updates that are distributed
|
||||
by the manufacturer in order to mitigate bugs in the microcode that released
|
||||
with the CPU that can cause real-world impact on what I do. Due to Facts and
|
||||
Circumstances that are immutable for the sake of argument, this microcode is not
|
||||
open source and cannot be compiled from source code. The linux-libre kernel
|
||||
removes the ability to load such firmware updates at runtime.
|
||||
|
||||
This means that if something like the FDIV bug or Spectre shows up again but it
|
||||
can be patched trivially with a microcode update, by nature of using the
|
||||
linux-libre kernel I am doomed until the base microcode gets updated from the
|
||||
motherboard manufacturer. If they release a closed-source update that you cannot
|
||||
inspect or modify.
|
||||
|
||||
This paternalistic view of "you shouldn't be able to load microcode updates
|
||||
because they aren't open source" means that my CPU will be vulnerable to
|
||||
potentially critical security flaws and I have no way to work around it. This
|
||||
ends up creating a _limitation_ in how I use my computer. This is worse than the
|
||||
limitations of proprietary hardware because there is the illusion of free choice
|
||||
that the community will spout off about as the next coming of sliced bread. That
|
||||
still doesn't change the fact that my wifi card won't work without the normal
|
||||
kernel and firmware blobs.
|
||||
|
||||
Combine this with other things like wifi card firmware (some wifi cards don't
|
||||
have the firmware stored on the device, they require the OS to send it firmware
|
||||
at runtime to make it work at all), and you have actually limited the agency and
|
||||
capability of users far, far more than if you just let them load the firmware in
|
||||
the first place.
|
||||
|
||||
[Yes, Yes the companies made the hardware this way in the first place and are
|
||||
responsible for the problem, but telling users they are wrong for wanting it to
|
||||
work because of an implementation detail about how the hardware updates itself
|
||||
feels a lot like victim blaming. I am aware of the Talos II being a magical
|
||||
puppy and rainbow situation where all of this isn't an issue, but sadly the
|
||||
world just didn't turn out that way and we have to deal with the results of
|
||||
it.](conversation://Cadey/coffee)
|
||||
|
||||
Consider a situation like wanting to play an online game together with friends,
|
||||
but through Facts and Circumstances you have an Nvidia GPU and the game is on
|
||||
Steam with no open source option. If you are using a fully open source operating
|
||||
system with no capacity to install Steam or the Nvidia drivers, you are screwed
|
||||
and thus your freedom to use your computer how you want is severely limited.
|
||||
|
||||
This also extends to how those Linux distributions handle things like AWS. AWS
|
||||
is largely the poster child of a proprietary cloud hosting platform that you are
|
||||
made to work with as part of your job. Consider if something like Parabola
|
||||
GNU/Linux created AWS images and gave users a best-in-class user experience for
|
||||
using them. This would make the net cost of using a highly auditable environment
|
||||
a lot lower than the current "don't use AWS lol" (which is again really close to
|
||||
victim blaming), and would also create institutional knowledge that would let
|
||||
other people benefit from this as a second or third order effect.
|
||||
|
||||
Parabola making AWS images means they can create more generic images, which
|
||||
means that other people can use those images to do whatever they want with their
|
||||
own hardware. This lets you have a net benefit to everyone in the project by
|
||||
decreasing the friction of using it, so it will in turn make users more likely
|
||||
to adopt it.
|
||||
|
||||
Remember the law of halves. Every additional step in adoption costs you half
|
||||
your audience. Spinning up an AWS instance to mess around with it is a very
|
||||
low-friction operation.
|
||||
|
||||
[But you can just not be a scrub and compile your own traitor kernel that lets
|
||||
you load freedom-violating binary blobs!](conversation://Numa/delet)
|
||||
|
||||
[Then you have to hope your CPU is good enough to build a kernel, hope you can
|
||||
pay attention to the kernel security mailing list enough to upgrade it when you
|
||||
need to and finally hope you can upgrade the firmware blobset that the kernel
|
||||
publishes separately! Hope is not a scalable strategy.](conversation://Cadey/angy)
|
||||
|
||||
If their goal is _really_ to liberate users and make it easy for them to have
|
||||
control over what their computer is doing, they should make it trivial to escape
|
||||
hatch into a less "pure" setup without having to install third party
|
||||
repositories that you just have to know about or sidestepping the upstream
|
||||
update process to install your own system software. This is more victim blaming.
|
||||
|
||||
The GNU project could be more than a circlejerk around things that the toe
|
||||
cheese god said in the 80's and 90's. They could have been a source of reverse
|
||||
engineering tools, institutions and overall inspire the kind of culture that
|
||||
would make it _easy_ to understand arbitrary hardware, platforms and software
|
||||
that you either come across or are made to use as a part of your job.
|
||||
|
||||
But they aren't. Instead, Guix, one of their if not their main flagship project
|
||||
for making a fully GNU system, is addled by the use of the linux-libre kernel.
|
||||
This makes the kernel fundamentally _incompatible_ with a shocking number of
|
||||
computers, thus limiting users' freedom to use Guix at all.
|
||||
|
||||
[But wait, isn't there that one nonguix project that allows you to install a
|
||||
normal kernel and Steam?](conversation://Mara/hmm)
|
||||
|
||||
[Yeah, but talk about that in the main #guix channel and you get told to not
|
||||
talk about it. You just have to know that it exists and you can't learn that it
|
||||
exists without knowing someone that tells you that it exists under the table,
|
||||
like some kind of underground software drug dealer giving you a hit of wifi card
|
||||
firmware. This means that knowledge of the nonguix project (which may contain
|
||||
tools that make it possible to use Guix at all) is hidden from users that may
|
||||
need it because it allows users to install proprietary software. This limits
|
||||
user freedom from being able to use their computer how they want by making it a
|
||||
potentially untrustable underground software den instead of something that can
|
||||
be properly handled upstream without having to place trust in too many
|
||||
places.](conversation://Cadey/angy)
|
||||
|
||||
[That hardware is defective by design and you shouldn't use
|
||||
it.](conversation://Numa/delet)
|
||||
|
||||
[Wow, thanks, I'm cured. My wifi card magically stopped existing and now
|
||||
everything is happy unicorns farting out rainbows that spawn free puppies and
|
||||
everything is saved forever.<br /><br />Again, that doesn't help me with the
|
||||
situation that my wifi card doesn't work and I as a user want it to even though
|
||||
making it work will require proprietary firmware. This shit is how you get
|
||||
things like the "GPL condom" in the Purism Librem phone, where all the
|
||||
proprietary firmware is rigged to be loaded automagically in hardware instead of
|
||||
sofware. This limits your ability to tinker with or modify the firmware _even if
|
||||
there are legitimate reasons such as critical updates_. So by making the
|
||||
hardware work with fully free software you have limited the ability to actually
|
||||
improve the state of the world even with the proprietary firmware the
|
||||
manufacturer gives you.](conversation://Cadey/angy)
|
||||
|
||||
Ubuntu gives the user more agency about how they want to use their computer than
|
||||
fully libre GNU/Linux distros ever can.
|
|
@ -0,0 +1,174 @@
|
|||
---
|
||||
title: Go net/http.ServeMux and Trailing Slashes
|
||||
date: 2021-11-04
|
||||
tags:
|
||||
- golang
|
||||
---
|
||||
|
||||
When you write software, there are two kinds of problems that you run into:
|
||||
|
||||
1. Problems that stretch your fundamental knowledge of how things work and as a
|
||||
result of solving them you become one step closer to unlocking the secrets to
|
||||
immortality and transcending beyond mere human limitations
|
||||
2. Exceedingly stupid typos that static analysis tools can't be taught how to
|
||||
catch and thus dooms humans to feel like they wasted so much time on
|
||||
something so trivial
|
||||
3. Off-by-one errors
|
||||
|
||||
Today I ran into one of these three types of problems.
|
||||
|
||||
[Buckle up, it's story time!](conversation://Cadey/coffee)
|
||||
|
||||
It's a Thursday morning. Everything in this project has been going smoothly.
|
||||
Almost too smoothly. Then `go test` is run to make sure that things are working like we expect.
|
||||
|
||||
[Huh, the test is passing, but the debug output says it should be failing.
|
||||
What's up with that? What's going on here?](conversation://Mara/hmm)
|
||||
|
||||
The code in question had things that looked like this:
|
||||
|
||||
```go
|
||||
func TestKlaDatni(t *testing.T) {
|
||||
tru := zbasuTurnis(t)
|
||||
ts := httptest.NewServer(tru)
|
||||
defer ts.Stop()
|
||||
|
||||
var buf bytes.Buffer
|
||||
failOnErr(t, json.NewEncoder(&buf).Encode(Renma{ Judri: "mara@cipra.jbo" }))
|
||||
|
||||
u, _ := url.Parse(ts.BaseURL)
|
||||
u.Path = "/api/v2/kla"
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, u.String(), &buf)
|
||||
failOnErr(t, err)
|
||||
|
||||
tru.InjectAuth(req)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
failOnErr(t, err)
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
t.Fatalf("wanted status code %d, got: %d", http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The error message looked like this:
|
||||
|
||||
```
|
||||
[INFO] turnis: invalid method GET for path /api/v2/kla
|
||||
```
|
||||
|
||||
[I'm not totally sure what's going on, let's dig into Turnis and see what it's
|
||||
doing. Surely we're missing something.](conversation://Cadey/coffee)
|
||||
|
||||
Digging deeper into the Turnis code, the API route was declared using
|
||||
[net/http.ServeMux](https://pkg.go.dev/net/http#ServeMux) like this:
|
||||
|
||||
```go
|
||||
mux.Handle("/api/v2/kla/", logWrap(tru.adminKla))
|
||||
```
|
||||
|
||||
[Maybe the `logWrap` middleware is changing it to `GET`
|
||||
somehow?](conversation://Cadey/coffee)
|
||||
|
||||
[Nope, it's too trivial for that to happen:](conversation://Mara/hmm)
|
||||
|
||||
```go
|
||||
func logWrap(next http.Handler) http.Handler {
|
||||
return xsweb.Falible(xsweb.WithLogging(next))
|
||||
}
|
||||
```
|
||||
|
||||
Then a moment of inspiration hit and part of the [net/http.ServeMux
|
||||
documentation](https://pkg.go.dev/net/http#ServeMux)
|
||||
came to mind. A ServeMux is basically a type that lets you associate HTTP paths
|
||||
with handler functions, kinda like this:
|
||||
|
||||
```
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", index)
|
||||
mux.HandleFunc("/robots.txt", robotsTxt)
|
||||
mux.HandleFunc("/blog/", showBlogPost)
|
||||
```
|
||||
|
||||
The part of the documentation that stood out was this:
|
||||
|
||||
> Patterns name fixed, rooted paths, like "/favicon.ico", or rooted subtrees,
|
||||
> like "/images/" (note the trailing slash). Longer patterns take precedence
|
||||
> over shorter ones, so that if there are handlers registered for both
|
||||
> "/images/" and "/images/thumbnails/", the latter handler will be called for
|
||||
> paths beginning "/images/thumbnails/" and the former will receive requests for
|
||||
> any other paths in the "/images/" subtree.
|
||||
|
||||
Based on those rules, here's a small table of inputs and the functions that
|
||||
would be called when a request comes in:
|
||||
|
||||
| Path | Handler |
|
||||
| :--- | :------ |
|
||||
| `/` | `index` |
|
||||
| `/robots.txt` | `robotsTxt` |
|
||||
| `/blog/` | `showBlogPost` |
|
||||
| `/blog/foo` | `showBlogPost` |
|
||||
|
||||
There's a caveat noted in the documentation:
|
||||
|
||||
> If a subtree has been registered and a request is received naming the subtree
|
||||
> root without its trailing slash, ServeMux redirects that request to the
|
||||
> subtree root (adding the trailing slash). This behavior can be overridden with
|
||||
> a separate registration for the path without the trailing slash. For example,
|
||||
> registering "/images/" causes ServeMux to redirect a request for "/images" to
|
||||
> "/images/", unless "/images" has been registered separately.
|
||||
|
||||
This means that the code from earlier that looked like this:
|
||||
|
||||
```go
|
||||
u.Path = "/api/v2/kla"
|
||||
```
|
||||
|
||||
wasn't actually going to the `tru.adminKla` function. It was getting redirected.
|
||||
This is because HTTP [doesn't allow you to redirect a POST
|
||||
request](https://support.postman.com/hc/en-us/articles/211913929-My-POST-request-is-redirected-to-a-GET-request).
|
||||
As a result, the POST request is getting downgraded to a GET request and the
|
||||
body is just lost forever.
|
||||
|
||||
[Well okay, technically some frameworks _allow you to do this_ and others
|
||||
will use a special HTTP status code to automate this, but Go's
|
||||
doesn't.](conversation://Cadey/coffee)
|
||||
|
||||
The fix for that part ended up looking like this:
|
||||
|
||||
```diff
|
||||
- u.Path = "/api/v2/kla"
|
||||
+ u.Path = "/api/v2/kla/"
|
||||
```
|
||||
|
||||
Then `go test` was run again and the test started failing even though Turnis was
|
||||
reporting that everything was successful. Then the final typo was spotted:
|
||||
|
||||
```diff
|
||||
- if resp.StatusCode == http.StatusOK {
|
||||
+ if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("wanted status code %d, got: %d", http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
```
|
||||
|
||||
<center>
|
||||
|
||||
![](https://cdn.christine.website/file/christine-static/stickers/cadey/percussive-maintenance.png)
|
||||
|
||||
</center>
|
||||
|
||||
[It took us 6 hours combined to figure this out. Is that okay? It feels like
|
||||
that's wasting too much time on a simple problem like
|
||||
that.](conversation://Mara/hmm)
|
||||
|
||||
[That's just how some of these kinds of problems are. The dumbest problems
|
||||
always take the longest to figure out because they are the ones that tools can't
|
||||
really warn you about. I once spent 15 hours of straight effort trying to fix
|
||||
something to find out that `ON` is a yaml value for "true" and that what I was
|
||||
trying to do needed to be `"ON"` instead. This is our lot in life as software
|
||||
people. You are going to make these kinds of mistakes and it is going to make
|
||||
you feel like an absolute buffoon every time. That is just how it happens. Let's
|
||||
go play Fortnite and forget about all this for
|
||||
now.](conversation://Cadey/coffee)
|
|
@ -0,0 +1,565 @@
|
|||
---
|
||||
title: Crimes with Go Generics
|
||||
date: 2022-04-24
|
||||
tags:
|
||||
- cursed
|
||||
- golang
|
||||
- generics
|
||||
vod:
|
||||
twitch: https://www.twitch.tv/videos/1465727432
|
||||
youtube: https://youtu.be/UiJtaKYQnzg
|
||||
---
|
||||
|
||||
Go 1.18 added [generics](https://go.dev/doc/tutorial/generics) to the
|
||||
language. This allows you to have your types take types as parameters
|
||||
so that you can create composite types (types out of types). This lets
|
||||
you get a lot of expressivity and clarity about how you use Go.
|
||||
|
||||
However, if you are looking for good ideas on how to use Go generics,
|
||||
this is not the post for you. This is full of bad ideas. This post is
|
||||
full of ways that you should not use Go generics in production. Do not
|
||||
copy the examples in this post into production. By reading this post
|
||||
you agree to not copy the examples in this post into production.
|
||||
|
||||
I have put my code for this article [on my git
|
||||
server](https://tulpa.dev/internal/gonads). This repo has been
|
||||
intentionally designed to be difficult to use in production by me
|
||||
taking the following steps:
|
||||
|
||||
1. I have created it under a Gitea organization named `internal`. This
|
||||
will make it impossible for you to import the package unless you
|
||||
are using it from a repo on my Gitea server. Signups are disabled
|
||||
on that Gitea server. See
|
||||
[here](https://go.dev/doc/go1.4#internalpackages) for more
|
||||
information about the internal package rule.
|
||||
1. The package documentation contains a magic comment that will make
|
||||
Staticcheck and other linters complain that you are using this
|
||||
package even though it is deprecated.
|
||||
|
||||
<xeblog-conv name="Mara" mood="hmm">What is that package
|
||||
name?</xeblog-conv>
|
||||
|
||||
<xeblog-conv name="Cadey" mood="enby">It's a reference to
|
||||
Haskell's monads, but adapted to Go as a pun.</xeblog-conv>
|
||||
|
||||
<xeblog-conv name="Numa" mood="delet">A gonad is just a gonoid in the
|
||||
category of endgofunctors. What's there to be confused
|
||||
about?</xeblog-conv>
|
||||
|
||||
<xeblog-conv name="Cadey" mood="facepalm">\*sigh\*</xeblog-conv>
|
||||
|
||||
## `Queue[T]`
|
||||
|
||||
To start things out, let's show off a problem in computer science that
|
||||
is normally difficult. Let's make a MPMS (multiple producer, multiple
|
||||
subscriber) queue.
|
||||
|
||||
First we are going to need a struct to wrap everything around. It will
|
||||
look like this:
|
||||
|
||||
```go
|
||||
type Queue[T any] struct {
|
||||
data chan T
|
||||
}
|
||||
```
|
||||
|
||||
This creates a type named `Queue` that takes a type argument `T`. This
|
||||
`T` can be absolutely anything, but the only requirement is that the
|
||||
data is a Go type.
|
||||
|
||||
You can create a little constructor for `Queue` instances with a
|
||||
function like this:
|
||||
|
||||
```go
|
||||
func NewQueue[T any](size int) Queue[T] {
|
||||
return Queue[T]{
|
||||
data: make(chan T, size),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now let's make some methods on the `Queue` struct that will let us
|
||||
push to the queue and pop from the queue. They could look like this:
|
||||
|
||||
```go
|
||||
func (q Queue[T]) Push(val T) {
|
||||
q.data <- val
|
||||
}
|
||||
|
||||
func (q Queue[T]) Pop() T {
|
||||
return <-q.data
|
||||
}
|
||||
```
|
||||
|
||||
These methods will let you put data at the end of the queue and then
|
||||
pull it out from the beginning. You can use them like this:
|
||||
|
||||
```go
|
||||
q := NewQueue[string](5)
|
||||
q.Push("hi there")
|
||||
str := q.Pop()
|
||||
if str != "hi there" {
|
||||
panic("string is wrong")
|
||||
}
|
||||
```
|
||||
|
||||
This is good, but the main problem comes from trying to pop from an
|
||||
empty queue. It'll stay there forever doing nothing. We can use the
|
||||
`select` statement to allow us to write a nonblocking version of the
|
||||
`Pop` function:
|
||||
|
||||
```go
|
||||
func (q Queue[T]) TryPop() (T, bool) {
|
||||
select {
|
||||
case val := <-q.data:
|
||||
return val, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
However when we try to compile this, we get an error:
|
||||
|
||||
```
|
||||
cannot use nil as T value in return statement
|
||||
```
|
||||
|
||||
In that code, `T` can be _anything_, including values that may not be
|
||||
able to be `nil`. We can work around this by taking advantage of the
|
||||
`var` statement, which makes a new variable and initializes it to the
|
||||
zero value of that type:
|
||||
|
||||
```go
|
||||
func Zero[T any]() T {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
```
|
||||
|
||||
When we run the `Zero` function like
|
||||
[this](https://go.dev/play/p/Z5tRs1-aKBU):
|
||||
|
||||
```go
|
||||
log.Printf("%q", Zero[string]())
|
||||
log.Printf("%v", Zero[int]())
|
||||
```
|
||||
|
||||
We get output that looks like this:
|
||||
|
||||
```
|
||||
2009/11/10 23:00:00 ""
|
||||
2009/11/10 23:00:00 0
|
||||
```
|
||||
|
||||
So we can adapt the `default` branch of `TryPop` to this:
|
||||
|
||||
```go
|
||||
func (q Queue[T]) TryPop() (T, bool) {
|
||||
select {
|
||||
case val := <-q.data:
|
||||
return val, true
|
||||
default:
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And finally write a test for good measure:
|
||||
|
||||
```go
|
||||
func TestQueue(t *testing.T) {
|
||||
q := NewQueue[int](5)
|
||||
for i := range make([]struct{}, 5) {
|
||||
q.Push(i)
|
||||
}
|
||||
|
||||
for range make([]struct{}, 5) {
|
||||
t.Log(q.Pop())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `Option[T]`
|
||||
|
||||
In Go, people use pointer values for a number of reasons:
|
||||
|
||||
1. A pointer value may be `nil`, so this can signal that the value may
|
||||
not exist.
|
||||
1. A pointer value only stores the offset in memory, so passing around
|
||||
the value causes Go to only copy the pointer instead of copying the
|
||||
value being passed around.
|
||||
1. A pointer value being passed to a function lets you mutate values
|
||||
in the value being passed. Otherwise Go will copy the value and you
|
||||
can mutate it all you want, but the changes you made will not
|
||||
persist past that function call. You can sort of consider this to
|
||||
be "immutable", but it's not as strict as something like passing
|
||||
`&mut T` to functions in Rust.
|
||||
|
||||
This `Option[T]` type will help us model the first kind of constraint:
|
||||
a value that may not exist. We can define it like this:
|
||||
|
||||
```go
|
||||
type Option[T any] struct {
|
||||
val *T
|
||||
}
|
||||
```
|
||||
|
||||
Then you can define a couple methods to use this container:
|
||||
|
||||
```go
|
||||
var ErrOptionIsNone = errors.New("gonads: Option[T] has no value")
|
||||
|
||||
func (o Option[T]) Take() (T, error) {
|
||||
if o.IsNone() {
|
||||
var zero T
|
||||
return zero, ErrOptionIsNone
|
||||
}
|
||||
|
||||
return *o.val, nil
|
||||
}
|
||||
|
||||
func (o *Option[T]) Set(val T) {
|
||||
o.val = &val
|
||||
}
|
||||
|
||||
func (o *Option[T]) Clear() {
|
||||
o.val = nil
|
||||
}
|
||||
```
|
||||
|
||||
Some other functions that will be useful will be an `IsSome` function
|
||||
to tell if the `Option` contains a value. We can use this to also
|
||||
implement an `IsNone` function that will let you tell if that `Option`
|
||||
_does not_ contain a value. They will look like this:
|
||||
|
||||
```go
|
||||
func (o Option[T]) IsSome() bool {
|
||||
return o.val != nil
|
||||
}
|
||||
|
||||
func (o Option[T]) IsNone() bool {
|
||||
return !o.IsSome()
|
||||
}
|
||||
```
|
||||
|
||||
We can say that if an Option does not have something in it, it has
|
||||
nothing in it. This will let us use `IsSome` to implement `IsNone`.
|
||||
|
||||
Finally we can add all this up to a `Yank` function, which is similar
|
||||
to
|
||||
[`Option::unwrap()`](https://doc.rust-lang.org/rust-by-example/error/option_unwrap.html)
|
||||
in Rust:
|
||||
|
||||
```go
|
||||
func (o Option[T]) Yank() T {
|
||||
if o.IsNone() {
|
||||
panic("gonads: Yank on None Option")
|
||||
}
|
||||
|
||||
return *o.val
|
||||
}
|
||||
```
|
||||
|
||||
This will all be verified in a Go test:
|
||||
|
||||
```go
|
||||
func TestOption(t *testing.T) {
|
||||
o := NewOption[string]()
|
||||
val, err := o.Take()
|
||||
if err == nil {
|
||||
t.Fatalf("[unexpected] wanted no value out of Option[T], got: %v", val)
|
||||
}
|
||||
|
||||
o.Set("hello friendos")
|
||||
_, err = o.Take()
|
||||
if err != nil {
|
||||
t.Fatalf("[unexpected] wanted no value out of Option[T], got: %v", err)
|
||||
}
|
||||
|
||||
o.Clear()
|
||||
if o.IsSome() {
|
||||
t.Fatal("Option should have none, but has some")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<xeblog-conv name="Mara" mood="hmm">I think that
|
||||
<code>Option[T]</code> will be the most useful outside of this post.
|
||||
It will need some work and generalization, but this may be something
|
||||
that the Go team will have to make instead of some random
|
||||
person.</xeblog-conv>
|
||||
|
||||
## `Thunk[T]`
|
||||
|
||||
In computer science we usually deal with values and computations.
|
||||
Usually we deal with one or the other. Sometimes computations can be
|
||||
treated as values, but this is very rare. It's even more rare to take
|
||||
a partially completed computation and use it as a value.
|
||||
|
||||
A thunk is a partially evaluated computation that is stored as a
|
||||
value. For an idea of what I'm talking about, let's consider this
|
||||
JavaScript function:
|
||||
|
||||
```javascript
|
||||
const add = (x, y) => x + y;
|
||||
console.log(add(2, 2)); // 4
|
||||
```
|
||||
|
||||
This creates a function called `add` that takes two arguments and
|
||||
returns one argument. This is great in many cases, but it makes it
|
||||
difficult for us to bind only one argument to the function and leave
|
||||
the other as a variable input. What if computing the left hand side of
|
||||
`add` is expensive and only needed once?
|
||||
|
||||
Instead we can write `add` like this:
|
||||
|
||||
```javascript
|
||||
const add = (x) => (y) => x + y;
|
||||
console.log(add(2)(2)); // 4
|
||||
```
|
||||
|
||||
This also allows us to make partially evaluated forms of `add` like
|
||||
`addTwo`:
|
||||
|
||||
```javascript
|
||||
const addTwo = add(2);
|
||||
console.log(addTwo(3)); // 5
|
||||
```
|
||||
|
||||
This can also be used with functions that do not take arguments, so
|
||||
you can pass around a value that isn't computed yet and then only
|
||||
actually compute it when needed:
|
||||
|
||||
```javascript
|
||||
const hypotenuse = (x, y) => Math.sqrt(x * x + y * y);
|
||||
const thunk = () => hypot(3, 4);
|
||||
```
|
||||
|
||||
You can then pass this thunk to functions _without having to evaluate
|
||||
it_ until it is needed:
|
||||
|
||||
```javascript
|
||||
dominateWorld(thunk); // thunk is passed as an unevaluated function
|
||||
```
|
||||
|
||||
We can implement this in Go by using a type like the following:
|
||||
|
||||
```go
|
||||
type Thunk[T any] struct {
|
||||
doer func() T
|
||||
}
|
||||
```
|
||||
|
||||
And then force the thunk to evaluate with a function such as `Force`:
|
||||
|
||||
```go
|
||||
func (t Thunk[T]) Force() T {
|
||||
return t.doer()
|
||||
}
|
||||
```
|
||||
|
||||
This works, however we can also go one step further than we did with
|
||||
the JavaScript example. We can take advantage of the `Thunk[T]`
|
||||
container to cache the result of the `doer` function so that calling
|
||||
it multiple times will only actually it once and return the same
|
||||
result.
|
||||
|
||||
<xeblog-conv name="Mara" mood="hacker">Keep in mind that this will
|
||||
only work for _pure functions_, or functions that don't modify the
|
||||
outside world. This isn't just global variables either, but any
|
||||
function that modifies any state anywhere, including network and
|
||||
filesystem IO.</xeblog-conv>
|
||||
|
||||
This would make `Thunk[T]` be implemented like this:
|
||||
|
||||
```go
|
||||
type Thunk[T any] struct {
|
||||
doer func() T // action being thunked
|
||||
o *Option[T] // cache for complete thunk data
|
||||
}
|
||||
|
||||
func (t *Thunk[T]) Force() T {
|
||||
if t.o.IsSome() {
|
||||
return t.o.Yank()
|
||||
}
|
||||
|
||||
t.o.Set(t.doer())
|
||||
return t.o.Yank()
|
||||
}
|
||||
|
||||
func NewThunk[T any](doer func() T) *Thunk[T] {
|
||||
return &Thunk[T]{
|
||||
doer: doer,
|
||||
o: NewOption[T](),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, for an overcomplicated example you can use this to implement the
|
||||
Fibonacci function. We can start out by writing a naiive Fibonacci
|
||||
function like this:
|
||||
|
||||
```go
|
||||
func Fib(n int) int {
|
||||
if n <= 1 {
|
||||
return n
|
||||
}
|
||||
|
||||
return Fib(n-1) + Fib(n-2)
|
||||
}
|
||||
```
|
||||
|
||||
We can turn this into a Go test in order to see how long it takes for
|
||||
it to work:
|
||||
|
||||
```go
|
||||
func TestRecurFib(t *testing.T) {
|
||||
t.Log(Fib(40))
|
||||
}
|
||||
```
|
||||
|
||||
Then when we run `go test`:
|
||||
|
||||
```console
|
||||
$ go test -run RecurFib
|
||||
=== RUN TestRecurFib
|
||||
thunk_test.go:15: 102334155
|
||||
--- PASS: TestRecurFib (0.36s)
|
||||
```
|
||||
|
||||
However, we can make this a lot more complicated with the power of the
|
||||
`Thunk[T]` type:
|
||||
|
||||
```go
|
||||
func TestThunkFib(t *testing.T) {
|
||||
cache := make([]*Thunk[int], 41)
|
||||
|
||||
var fib func(int) int
|
||||
fib = func(n int) int {
|
||||
if cache[n].o.IsSome() {
|
||||
return *cache[n].o.val
|
||||
}
|
||||
return fib(n-1) + fib(n-2)
|
||||
}
|
||||
|
||||
for i := range cache {
|
||||
i := i
|
||||
cache[i] = NewThunk(func() int { return fib(i) })
|
||||
}
|
||||
cache[0].o.Set(0)
|
||||
cache[1].o.Set(1)
|
||||
|
||||
t.Log(cache[40].Force())
|
||||
}
|
||||
```
|
||||
|
||||
And then run the test:
|
||||
|
||||
```
|
||||
=== RUN TestThunkFib
|
||||
thunk_test.go:36: 102334155
|
||||
--- PASS: TestThunkFib (0.60s)
|
||||
```
|
||||
|
||||
<xeblog-conv name="Mara" mood="hmm">Why is this so much slower? This
|
||||
should be caching the intermediate values. Maybe something like this
|
||||
would be faster? This should complete near instantly,
|
||||
right?</xeblog-conv>
|
||||
|
||||
```go
|
||||
func TestMemoizedFib(t *testing.T) {
|
||||
mem := map[int]int{
|
||||
0: 0,
|
||||
1: 1,
|
||||
}
|
||||
|
||||
var fib func(int) int
|
||||
fib = func(n int) int {
|
||||
if result, ok := mem[n]; ok {
|
||||
return result
|
||||
}
|
||||
|
||||
result := fib(n-1) + fib(n-2)
|
||||
mem[n] = result
|
||||
return result
|
||||
}
|
||||
|
||||
t.Log(fib(40))
|
||||
}
|
||||
```
|
||||
|
||||
```console
|
||||
$ go test -run Memoized
|
||||
=== RUN TestMemoizedFib
|
||||
thunk_test.go:35: 102334155
|
||||
--- PASS: TestMemoizedFib (0.00s)
|
||||
```
|
||||
|
||||
<xeblog-conv name="Cadey" mood="enby">I'm not sure
|
||||
either.</xeblog-conv>
|
||||
|
||||
If you change the `fib` function to this, it works, but it also steps
|
||||
around the `Thunk[T]` type:
|
||||
|
||||
```go
|
||||
fib = func(n int) int {
|
||||
if cache[n].o.IsSome() {
|
||||
return *cache[n].o.val
|
||||
}
|
||||
|
||||
result := fib(n-1) + fib(n-2)
|
||||
cache[n].o.Set(result)
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
This completes instantly:
|
||||
|
||||
```
|
||||
=== RUN TestThunkFib
|
||||
thunk_test.go:59: 102334155
|
||||
--- PASS: TestThunkFib (0.00s)
|
||||
```
|
||||
|
||||
To be clear, this isn't the fault of Go generics. I'm almost certain
|
||||
that my terrible code is causing this to be much slower.
|
||||
|
||||
<xeblog-conv name="Numa" mood="delet">This is the power of gonads:
|
||||
making easy code complicated, harder to reason about and slower than
|
||||
the naiive approach! Why see this as terrible code when it creates an
|
||||
amazing opportunity for cloud providers to suggest that people use
|
||||
gonads' `Thunk[T]` so that they use more CPU and then have to pay cloud
|
||||
providers more money for CPU! Think about the children!</xeblog-conv>
|
||||
|
||||
---
|
||||
|
||||
<xeblog-conv name="Cadey" mood="coffee">EDIT(2022 M04 25 05:56): amscanne on
|
||||
Hacker News pointed out that my code was in fact wrong. My `fib` function should
|
||||
have been a lot simpler.</xeblog-conv>
|
||||
|
||||
```go
|
||||
fib = func(n int) int {
|
||||
return cache[n-1].Force() + cache[n-2].Force()
|
||||
}
|
||||
```
|
||||
|
||||
<xeblog-conv name="Cadey" mood="facepalm">Applying this also makes the code run
|
||||
instantly as I'd expect. I knew _something_ was _very wrong_, but I never
|
||||
expected something this stupid. Thanks amscanne!</xeblog-conv>
|
||||
|
||||
<xeblog-conv name="Numa" mood="happy">Hey, it makes for good surrealism. If that
|
||||
isn't a success, what is?</xeblog-conv>
|
||||
|
||||
---
|
||||
|
||||
I'm glad that Go has added generics to the language. It's certainly
|
||||
going to make a lot of things a lot easier and more expressive. I'm
|
||||
worried that the process of learning how to use generics in Go is
|
||||
going to create a lot of churn and toil as people get up to speed on
|
||||
when and where they should be used. These should be used in specific
|
||||
cases, not as a bread and butter tool.
|
||||
|
||||
I hope this was an interesting look into how you can use generics in
|
||||
Go, but again please don't use these examples in production.
|
|
@ -3,9 +3,6 @@ title: "gopreload: LD_PRELOAD for the Gopher crowd"
|
|||
date: "2017-03-25"
|
||||
---
|
||||
|
||||
gopreload: LD_PRELOAD for the Gopher crowd
|
||||
==========================================
|
||||
|
||||
A common pattern in Go libraries is to take advantage of [init functions][initf]
|
||||
to do things like settings up defaults in loggers, automatic metrics instrumentation,
|
||||
flag values, [debugging tools][manhole] or database drivers. With monorepo culture
|
||||
|
|
|
@ -4,10 +4,9 @@ date: 2019-01-11
|
|||
thanks: https://github.com/dreampuf/GraphvizOnline
|
||||
---
|
||||
|
||||
# [graphviz.christine.website](https://graphviz.christine.website)
|
||||
|
||||
I have been using an [online copy of GraphViz](https://github.com/dreampuf/GraphvizOnline)
|
||||
for a while to make my own diagrams online. I have forked this to [here](https://github.com/Xe/GraphvizOnline) and added basic [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) support.
|
||||
Here is the [link](https://graphviz.christine.website).
|
||||
|
||||
Here's an [example usage video](https://youtu.be/IUvbtK_nmtY).
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ for: Mother Aya
|
|||
series: magick
|
||||
---
|
||||
|
||||
# Gratitude
|
||||
|
||||
A lot of ground has been trodden about Mindfulness and its many facets, but there is one topic I have seen not enough people elaborate on, especially in a satisfactory manner, and that topic is gratitude.
|
||||
|
||||
The act of expressing gratitude is a behaviour that grounds you in observation of the present moment; of the present you, and of what matters to that present you. It can help you understand the current, immediate moment, the Now, by pushing you to examine parts of it that you might have taken for granted. Or parts that hide behind the other parts. It is a tool of positive exploration, that empowers the user to iteratively discern the heart of matters, of things, guided by the unerring principle of genuine appreciation of what counts.
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2021-06-13
|
|||
author: Heartmender
|
||||
---
|
||||
|
||||
# Using Paper for Everyday Tasks
|
||||
|
||||
I have a bit of a reputation of being a very techno-savvy person. People have
|
||||
had the assumption that I have some kind of superpowerful handcrafted task
|
||||
management system that rivals all other systems and fully integrates with
|
||||
|
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- release
|
||||
---
|
||||
|
||||
# The h Programming Language
|
||||
|
||||
[h](https://h.christine.website) is a project of mine that I have released
|
||||
recently. It is a single-paradigm, multi-tenant friendly, turing-incomplete
|
||||
programming language that does nothing but print one of two things:
|
||||
|
@ -22,16 +20,16 @@ for browsers, but I've been using it for server-side tasks.
|
|||
|
||||
I have written more about/with WebAssembly in the past in these posts:
|
||||
|
||||
- https://christine.website/talks/webassembly-on-the-server-system-calls-2019-05-31
|
||||
- https://christine.website/blog/olin-1-why-09-1-2018
|
||||
- https://christine.website/blog/olin-2-the-future-09-5-2018
|
||||
- https://christine.website/blog/land-1-syscalls-file-io-2018-06-18
|
||||
- https://christine.website/blog/templeos-2-god-the-rng-2019-05-30
|
||||
- https://xeiaso.net/talks/webassembly-on-the-server-system-calls-2019-05-31
|
||||
- https://xeiaso.net/blog/olin-1-why-09-1-2018
|
||||
- https://xeiaso.net/blog/olin-2-the-future-09-5-2018
|
||||
- https://xeiaso.net/blog/land-1-syscalls-file-io-2018-06-18
|
||||
- https://xeiaso.net/blog/templeos-2-god-the-rng-2019-05-30
|
||||
|
||||
This is a continuation of the following two posts:
|
||||
|
||||
- https://christine.website/blog/the-origin-of-h-2015-12-14
|
||||
- https://christine.website/blog/formal-grammar-of-h-2019-05-19
|
||||
- https://xeiaso.net/blog/the-origin-of-h-2015-12-14
|
||||
- https://xeiaso.net/blog/formal-grammar-of-h-2019-05-19
|
||||
|
||||
All of the relevant code for h is [here](https://github.com/Xe/x/tree/master/cmd/h).
|
||||
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
title: "I Miss Heroku's DevEx"
|
||||
date: 2022-05-12
|
||||
---
|
||||
|
||||
If you've never really experienced it before, it's gonna sound really weird.
|
||||
Basically the main way that Heroku worked is that they would set up a git remote
|
||||
for each "app" it hosted. Each "app" had its source code in a git repo and a
|
||||
"Procfile" that told Heroku what to do with it. So when it came time to deploy
|
||||
that app, you'd just `git push heroku main` and then Heroku would just go off
|
||||
and build that app and run it _somewhere_ in the cloud. You got back a HTTPS URL
|
||||
and then bam you have a website.
|
||||
|
||||
The developer experience didn't stop there. Most of how Heroku apps are
|
||||
configured are via environment variables, and there were addons that let you
|
||||
tell Heroku things like "hi yes I would like one (1) postgres please" and the
|
||||
platform would spin up a database somewhere and drop a config variable into the
|
||||
app's config. It was magic. Things just worked and it left you free to go do
|
||||
what made you money.
|
||||
|
||||
Heroku's free tier got me the in I needed to make my career really start. If I
|
||||
didn't have something like Heroku in my life I doubt that my career would be the
|
||||
same or even I would be the same person I am today. It's really hard to describe
|
||||
what having access to a platform that lets you turn ideas into production
|
||||
quality code does to your output ability. I even ended up reinventing Heroku a
|
||||
few times in my career (working for Deis and later reinventing most of the core
|
||||
of Heroku as a project between jobs), but nothing really hit that same level of
|
||||
wonder/magic that Heroku did.
|
||||
|
||||
I ended up working there and when I did I understood why Heroku had fallen so
|
||||
much. Heroku is owned by Salesforce and Salesforce doesn't really understand
|
||||
what they had acquired with Heroku. Heroku had resisted integration into the
|
||||
larger Salesforce organization and as a result was really really starved for
|
||||
headcount. I had to have a come-to-jesus meeting with the CTO of Heroku where I
|
||||
spelled out my medical needs and how the insurance that the contracting agency
|
||||
they were using was insufficent (showing comparisons between bills for blood
|
||||
draws where paying with the insurance ended up costing me more than not using
|
||||
it). I got hired and then that was just in time for Salesforce to really start
|
||||
pulling Heroku into the fold.
|
||||
|
||||
The really great part about working at Heroku was that setting up a new service
|
||||
was so easy that the majority of the productionalization checklist was just
|
||||
enabling hidden feature flags to lock down the app. I'm surprised that didn't
|
||||
get streamlined.
|
||||
|
||||
The Heroku I joined no longer exists. I joined Heroku but I left Salesforce. I
|
||||
can't blame any of my coworkers from Heroku from fleeing the sinking ship. The
|
||||
ship has been sinking for years but the culture of Heroku really stuck around
|
||||
long enough that it was hard to realize the ship was sinking.
|
||||
|
||||
It can really be seen with how long it's taken Heroku to react to [that one
|
||||
horrible security event](https://status.heroku.com/incidents/2413) they've been
|
||||
dealing with. Based on what I remember about the internal architecture (it was a
|
||||
microservices tire fire unlike you have ever seen, it's part of the inspiration
|
||||
that lead me to write [this post](/blog/make-microservices-cluster-2022-01-27))
|
||||
and the notes that have been put on the public facing status page, I'm guessing
|
||||
that most of Heroku is "legacy" code (IE: nobody on the team that made this
|
||||
service works here anymore) at this point. When I was there most of the services
|
||||
on my team were "legacy" code that was production-facing, load-bearing and
|
||||
overall critical to the company succeeding; but it was built to be reliable
|
||||
enough that we could overall ignore it until it was actually falling over. But
|
||||
then because of the ways that things were chorded together it could take a very
|
||||
long time to actually fix issues because the symptoms were all over the place.
|
||||
|
||||
Don't get me wrong, I loved working there but it was mostly for the people. That
|
||||
and the ability to say that I helped make Heroku better for the next generation.
|
||||
If you've ever used the metrics tab on Heroku, chances are that you've
|
||||
encountered my code indirectly. If you've ever done Heroku threshold autoscaling
|
||||
or response time alerting, you've dealt with code I helped write. The body of
|
||||
Heroku remains but the soul has long since fled.
|
||||
|
||||
At the few points of my career that I have tried to reinvent Heroku (be it on my
|
||||
own or working for a company doing that), there has mostly been this weird
|
||||
realization that in order to have a thing like Heroku exist it really needs to
|
||||
be hosted by someone else in the cloud. One of the places I worked for was
|
||||
selling self-hosted Heroku on top of CoreOS and fleetd (remember fleetd? that
|
||||
was magical) and while it did have a lot of the same developer experience, it
|
||||
never really had the same magic feeling. I had the same problem with my own
|
||||
implementation. Sure you can get the app hosting part of Heroku fairly easily
|
||||
(and with Docker being as mature as it was at that point yeah it was fairly
|
||||
easy). But when it comes to the real experience of addons and the whole
|
||||
ecosystem there, you really need either to get very lucky or become an industry
|
||||
standard. Realistically though, you aren't going to be either lucky or an
|
||||
industry standard and then you need to also reinvent the next 80% of Heroku from
|
||||
scratch on hardware that you don't control. It's no wonder that ultimately
|
||||
failed (even though one of them was bought out by Microsoft after doing a weird
|
||||
Kubernetes pivot).
|
||||
|
||||
There was something really magical about the whole thing that I really miss to
|
||||
this day. Heroku was at least a decade ahead of its time as far as developer
|
||||
experience goes. Things Just Worked in ways that would probably put a lot of us
|
||||
out of jobs if they really took off. I miss the process for putting something on
|
||||
the internet to just be a `git push` and trust that the machine will just take
|
||||
care of it. I wonder if we'll ever really have something like that on top of Nix
|
||||
or NixOS.
|
||||
|
||||
---
|
||||
|
||||
If you're reading this before the 12th, welcome to an experiment! I've been
|
||||
wondering about how to make some of my posts Patreon exclusive for a week. This
|
||||
post was published for my patrons on the 5th of May. Please don't share this
|
||||
link around on social media until the 12th, but privately sharing it is okay.
|
|
@ -6,8 +6,6 @@ tags:
|
|||
- satire
|
||||
---
|
||||
|
||||
# hlang in 30 Seconds
|
||||
|
||||
hlang (the h language) is a revolutionary new use of WebAssembly that enables
|
||||
single-paridigm programming without any pesky state or memory accessing. The
|
||||
simplest program you can use in hlang is the h world program:
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2017-12-10
|
|||
series: when-then-zen
|
||||
---
|
||||
|
||||
# How does into Meditation
|
||||
|
||||
tl;dr
|
||||
|
||||
1. stop thinking
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- philosophy
|
||||
---
|
||||
|
||||
# How HTTP Requests Work
|
||||
|
||||
Reading this webpage is possible because of millions of hours of effort with
|
||||
tens of thousands of actors across thousands of companies. At some level it's a
|
||||
minor miracle that this all works at all. Here's a preview into the madness that
|
||||
|
@ -16,7 +14,7 @@ goes into hitting enter on christine.website and this website being loaded.
|
|||
|
||||
## Beginnings
|
||||
|
||||
The user types in `https://christine.website` into the address bar and hits
|
||||
The user types in `https://xeiaso.net` into the address bar and hits
|
||||
enter on the keyboard. This sends a signal over USB to the computer and the
|
||||
kernel polls the USB controller for a new message. It's recognized as from the
|
||||
keyboard. The input is then sent to the browser through an input driver talking
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- rust
|
||||
---
|
||||
|
||||
# How I Start: Nix
|
||||
|
||||
[Nix][nix] is a tool that helps people create reproducible builds. This means that
|
||||
given a known input, you can get the same output on other machines. Let's build
|
||||
and deploy a small Rust service with Nix. This will not require the Rust compiler
|
||||
|
|
|
@ -8,8 +8,6 @@ tags:
|
|||
- nix
|
||||
---
|
||||
|
||||
# How I Start: Rust
|
||||
|
||||
[Rust][rustlang] is an exciting new programming language that makes it easy to
|
||||
make understandable and reliable software. It is made by Mozilla and is used by
|
||||
Amazon, Google, Microsoft and many other large companies.
|
||||
|
@ -48,7 +46,7 @@ the Rust compiler.
|
|||
|
||||
[nixos]: https://nixos.org/nixos/
|
||||
[nix]: https://nixos.org/nix/
|
||||
[howistartnix]: https://christine.website/blog/how-i-start-nix-2020-03-08
|
||||
[howistartnix]: https://xeiaso.net/blog/how-i-start-nix-2020-03-08
|
||||
|
||||
## A new project
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- markdown
|
||||
---
|
||||
|
||||
# How Mara Works
|
||||
|
||||
Recently I introduced Mara to this blog and I didn't explain much of the theory
|
||||
and implementation behind them in order to proceed with the rest of the post.
|
||||
There was actually a significant amount of engineering that went into
|
||||
|
|
|
@ -7,8 +7,6 @@ tags:
|
|||
- email
|
||||
---
|
||||
|
||||
# How to Send Email with Nim
|
||||
|
||||
Nim offers an [smtp][nimsmtp] module, but it is a bit annoying to use out of the
|
||||
box. This blogpost hopes to be a mini-tutorial on the basics of how to use the
|
||||
smtp library and give developers best practices for handling outgoing email in
|
||||
|
|
|
@ -8,12 +8,10 @@ tags:
|
|||
|
||||
<span style="color: #cc241d"><big><big><big>CONTENT WARNING</big></big></big></span>
|
||||
|
||||
This post is going to talk about people that try to target children for sexual favors. You are not required to read this. If you are prone to anxiety I absolutely cannot reccomend reading this post. Dealing with the situations that lead me to write this post (and doing the research that has lead to learning how to do this) has caused me to lose a lot of sleep over the last month.
|
||||
This post is going to talk about people that try to target children for sexual favors. You are not required to read this. If you are prone to anxiety I absolutely cannot recommend reading this post. Dealing with the situations that lead me to write this post (and doing the research that has lead to learning how to do this) has caused me to lose a lot of sleep over the last month.
|
||||
|
||||
It is my hope that this post is NOT useful to readers. If it ever becomes useful I suggest crying a bit. Yes, seriously.
|
||||
|
||||
# How to Handle Pedophiles in Communities
|
||||
|
||||
For better or worse since Covid started pushing everyone indoors and online, a lot of online spaces that were usually populated by adults have become populated with a lot more people that are under the age of consent/majority. This is obviously not the most ideal, as it ends up making that community a target for pedophiles. I want to be clear though, this kind of thing is a black swan kind of event, not something that happens commonly. However when it does happen, oh god it **HAPPENS**.
|
||||
|
||||
For the rest of this article I'm going to assume a few things in how I direct my advice:
|
||||
|
@ -24,7 +22,7 @@ For the rest of this article I'm going to assume a few things in how I direct my
|
|||
|
||||
## Don't Panic
|
||||
|
||||
First, don't panic. This is going to be a stressful and scary thing. This is normal. You are feeling that feeling that you are feeling and it is happening. It is going to suck. You are going to lose sleep. This is something that is happening because you care about that community, and if you didn't care about it you would not be having these feelings. If you feel the need, cry about it. Let the emotions out instead of bottling them up. This sounds like a dumb meme or whatever but I am being dead serious in this reccomendation.
|
||||
First, don't panic. This is going to be a stressful and scary thing. This is normal. You are feeling that feeling that you are feeling and it is happening. It is going to suck. You are going to lose sleep. This is something that is happening because you care about that community, and if you didn't care about it you would not be having these feelings. If you feel the need, cry about it. Let the emotions out instead of bottling them up. This sounds like a dumb meme or whatever but I am being dead serious in this recommendation.
|
||||
|
||||
So, now, one of the first things you need to do is review the terms and conditions of the platform you are moderating the community on.
|
||||
|
||||
|
@ -44,13 +42,13 @@ When you are getting evidence from the minor, make sure that the evidence is in
|
|||
|
||||
Once you have the information and have reviewed it, open [Gimp](https://www.gimp.org) and run the screenshots through the edge detection filter. This filter will allow you to look for any obvious signs of the text in the screenshot being doctored. Certain kinds of people have been known to fake reports and screenshots of someone doing something untoward to a child as a way to get them removed from a community. This will help you weed them out. It sounds heartless to say it like this, but this is something that you _actually do_ end up seeing happen sometimes so it is worth mentioning.
|
||||
|
||||
If anyone on the moderation team ends up leaking the information about thise research, contents of the research, people involved in the event or anything of the sort to the person being investigated: flat-out ban them without any chance of appeal. That gives the person being investigated a chance to delete information that would hinder any hope of investigating the situation.
|
||||
If anyone on the moderation team ends up leaking the information about this research, contents of the research, people involved in the event or anything of the sort to the person being investigated: flat-out ban them without any chance of appeal. That gives the person being investigated a chance to delete information that would hinder any hope of investigating the situation.
|
||||
|
||||
## Reporting to the Platform
|
||||
|
||||
Once you have the bumdle of information, identifiers and more, then you need to open a ticket with the trust and safety team of the platform you are on (however if this is a self-hosted platform either contact the service administrator or if you are the service administrator then you can skip to the next step involving the FBI). Give them all the information you have. Explain the situation as best as you can.
|
||||
Once you have the bundle of information, identifiers and more, then you need to open a ticket with the trust and safety team of the platform you are on (however if this is a self-hosted platform either contact the service administrator or if you are the service administrator then you can skip to the next step involving the FBI). Give them all the information you have. Explain the situation as best as you can.
|
||||
|
||||
When you send the report to the platform itself, it is _very unlikely_ you will get any more information from the platform. You are likely going to get an email that says they've confirmed recipt of the information and that email will usually contain something about the situation being confidential inside the moderation team of the plaform. This is normal, and is part of a legal "covering my ass" kind of situation.
|
||||
When you send the report to the platform itself, it is _very unlikely_ you will get any more information from the platform. You are likely going to get an email that says they've confirmed recipt of the information and that email will usually contain something about the situation being confidential inside the moderation team of the platform. This is normal, and is part of a legal "covering my ass" kind of situation.
|
||||
|
||||
## Reporting to the FBI or Similar
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2018-03-29
|
|||
series: howto
|
||||
---
|
||||
|
||||
# How to Automate Discord Message Posting With Webhooks and Cron
|
||||
|
||||
Most Linux systems have [`cron`](https://en.wikipedia.org/wiki/Cron) installed to run programs at given intervals. An example usecase would be to install package updates every Monday at 9 am (keep the sysadmins awake!).
|
||||
|
||||
Discord lets us post things using [webhooks](https://discordapp.com/developers/docs/resources/webhook). Combining this with cron lets us create automated message posting bots at arbitrary intervals.
|
||||
|
|
|
@ -4,8 +4,6 @@ date: 2019-07-07
|
|||
series: howto
|
||||
---
|
||||
|
||||
# How to Use User Mode Linux
|
||||
|
||||
[User Mode Linux](http://user-mode-linux.sourceforge.net) is a port of the
|
||||
[Linux kernel](https://www.kernel.org) to itself. This allows you to run a
|
||||
full blown Linux kernel as a normal userspace process. This is used by kernel
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue