1
0
Fork 0

New post: Workaround for external keyboards to make special characters in KOReader

This commit is contained in:
Lethe Beltane 2023-09-01 07:16:19 -05:00
parent 1a73474b6e
commit ab1a8afcf2
No known key found for this signature in database
GPG Key ID: 21A3DA3DE29CB63C
15 changed files with 102 additions and 18 deletions

View File

@ -29,7 +29,7 @@
<p>You mean... onboarding hasn't been made easy for non-technical people? The same people all these grand overtures of "escaping from MEGACORP" are supposed to save? Or is this one of those "citadel" projects where all the benefit is for the early adopters safe inside and the masses are supposed to be locked outside to suffer whatever computing apocalypse will come?</p>
<p>Urbit has a free version of an identity called a "comet", but apparently <a href="https://archive.ph/pOszH#selection-293.184-293.206">it can't download any apps or interact with much of the network</a>,<!-- https://urbit.org/getting-started/desktop -->
which is confusingly later <a href="https://web.archive.org/web/20220805172516/https://urbit.org/getting-started/cli#boot-your-planet">contradicted in the CLI install instructions: "There are currently few differences between using a comet-level identity and a planet-level one."</a> To do anything of substance, you'll "need a to get a planet". Because I already had my Urbit passport from three years ago, the post doesn't end here, and I was able to continue my research without spending any money. Otherwise, judging from the <a href="https://web.archive.org/web/20220730150142/https://urbit.org/getting-started/get-planet">recommended planet resellers</a> that were functional, prices for a Layer 2 planet range from about $15 to $50, which isn't an "I am now destitute and living on the streets" amount of money... but still, that's a lot of groceries.</p>
<p>The desktop GUI, according to the documentation, requires <code>snap</code> to be installed, but some digging reveals <a href="https://github.com/urbit/port/releases">there are also <code>.dpkg</code> packages and raw binaries</a>... which, par for the course of web3 bullshit, are written in Node.js. However, these seem to only be available for x86_64, unless you're using a Mac, in which case you also get <code>arm64</code>, or a Raspberry Pi, in which case you get shunted to a <a href="https://web.archive.org/web/20220730152509/https://github.com/OdysLam/home-urbit">a third-party solution</a>. You could also attempt to compile it yourself, but given the aforementioned Node.js dependency, you're more likely to see the sun explode tomorrow than <a href="../../2020/february/32bit.html">get the damn thing to compile properly</a>.</p>
<p>The desktop GUI, according to the documentation, requires <code>snap</code> to be installed, but some digging reveals <a href="https://github.com/urbit/port/releases">there are also <code>.dpkg</code> packages and raw binaries</a>... which, par for the course of web3 bullshit, are written in Node.js. However, these seem to only be available for x86_64, unless you're using a Mac, in which case you also get <code>arm64</code>, or a Raspberry Pi, in which case you get shunted to <a href="https://web.archive.org/web/20220730152509/https://github.com/OdysLam/home-urbit">a third-party solution</a>. You could also attempt to compile it yourself, but given the aforementioned Node.js dependency, you're more likely to see the sun explode tomorrow than <a href="../../2020/february/32bit.html">get the damn thing to compile properly</a>.</p>
<p>Because I wasn't sure how much bandwidth Urbit would use, even though I have a Wi-Fi repeater in my bedroom now and thus an actually decent connection, I instead opted for the server install, which entails <a href="https://urbit.org/getting-started/server#install-urbit-via-the-command-line">downloading a shady-looking CLI binary</a> and feeding it a keyfile... which supposedly comes with the passport, but mine didn't have one, and the setup instructions make it too easy to accidentally skip over the part where you can redownload said keyfile at <a href="https://bridge.urbit.org">bridge.urbit.org</a> in the "OS" menu at the bottom of the page.</p>
<p>It took what felt like forever (at least ten minutes; I timed it) to get to a prompt after running <code>~/urbit/urbit -p 57323 -w socleb-fosrut -k ./socleb-fosrut.key</code>. The web interface, the port to run on specified with the <code>-p</code> option, completely ignored this argument and instead decided to run on port 8081, which thankfully wasn't claimed by any other process at the time. You still need the CLI running in a separate window, though, because you'll need to run <code>+code</code> in the "dojo" (Urbit speak for the CLI) to generate a code to log in to the web interface.</p>
<p>On first run, there are only three options in the web UI: "Terminal", "Groups", and "Bitcoin". I tried Terminal first. It appeared that whatever I typed into it was immediately mirrored in the CLI window. I typed <code>help</code> thinking it would give me a list of commands like it does in Bash, but instead I got the nonsensical string <code>&lt;1.lqz [* &lt;232.hhi 51.qbt 123.ppa 46.hgz 1.pnw %140&gt;]&gt;</code>. (At least it has an angel number...?)</p>

View File

@ -15,7 +15,7 @@
</div>
<hr>
<div class="box">
<p>The nice thing about being the admin of Let's Decentralize is that, whenever I wish there was a way to do something on the Internet anonymously, I already have a mental record of which of those things I can do simply by hopping onto Tor Browser. Need to look at a public Twitter feed? <a href="http://xanthexikes7btjqlkakrxjf546rze2n4ftnqzth6qk52jdgrf6jwpqd.onion/rollcall/tor.html#nitter">Peep that shit using a Nitter instance</a>. Need to look up a weird health symptom or something potentially incriminating (like if it's spelled sodium <em>nitrite</em> with an I or <em>nitrate</em> with an A)? <a href="http://xanthexikes7btjqlkakrxjf546rze2n4ftnqzth6qk52jdgrf6jwpqd.onion/rollcall/tor.html#searx">Searx instances</a> have an awfully hard time tracking <code>127.0.0.1</code>. Publishing code for a project that enables the user to do something illegal, like <a href="https://web.archive.org/web/20221022233636/https://deemix.app/">download massive amounts of music off Deezer</a>? Codeberg and Notabug are pretty Tor-friendly, but you can do one better by <a href="https://letsdecentralize.org/rollcall/gits.md">using a hidden service</a>.</p>
<p>The nice thing about being the admin of Let's Decentralize is that, whenever I wish there was a way to do something on the Internet anonymously, I already have a mental record of which of those things I can do simply by hopping onto Tor Browser. Need to look at a public Twitter feed? <a href="http://hikariu7kodaqrmvu3c3y422r6jc7gqtpvvbry6u7ajvranukx6gszqd.onion/rollcall/tor.html#nitter">Peep that shit using a Nitter instance</a>. Need to look up a weird health symptom or something potentially incriminating (like if it's spelled sodium <em>nitrite</em> with an I or <em>nitrate</em> with an A)? <a href="http://hikariu7kodaqrmvu3c3y422r6jc7gqtpvvbry6u7ajvranukx6gszqd.onion/rollcall/tor.html#searx">Searx instances</a> have an awfully hard time tracking <code>127.0.0.1</code>. Publishing code for a project that enables the user to do something illegal, like <a href="https://web.archive.org/web/20221022233636/https://deemix.app/">download massive amounts of music off Deezer</a>? Codeberg and Notabug are pretty Tor-friendly, but you can do one better by <a href="https://letsdecentralize.org/rollcall/gits.md">using a hidden service</a>.</p>
<p>Unfortunately I also have a bad habit of <a href="../september/browsers.html">giving moids on the Internet the time of day</a> and falling victim to <a href="https://web.archive.org/web/20221022234415/https://lifehacker.com/what-cunninghams-law-really-tells-us-about-how-we-inter-1848733445">Cunningham's law</a>. So when I booted up <a href="https://codeberg.org/lethe/beres">Beres</a>, the worst RSS feed reader in existence (I should know; I made the damn thing), and saw that our (formerly-)favorite moid was <a href="https://archive.ph/S4Q8R">failing at technology <em>yet</em> again</a>, naturally I felt the urgent need to respond. Thankfully I managed to calm myself before sitting down to write this post. I decided to not make you slog through a misandrist rant. You're welcome!</p>
<p>The argument of the aforementioned article is twofold:</p>
<ol>

View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Workaround for external keyboards to make special characters in KOReader - Archive - MayVaneDay Studios</title>
<link href="../../../style.css" rel="stylesheet" type="text/css" media="all">
<meta name="author" content="Vane Vander">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body class="mayvaneday">
<article>
<div class="box">
<h1>Workaround for external keyboards to make special characters in KOReader</h1>
<p>published: 2023-09-01</p>
</div>
<hr>
<div class="box">
<p>For a while, I've fantasized about turning my little Kobo Libra H2O, an e-reader that runs an embedded and bare-bones version of Linux, into <a href="https://letsdecentralize.org/tutorials/kobo-terminal.html">a more general-purpose computing device</a>. You know, in case the apocalypse hits and somehow all my other devices eventually go to shit. For a while I've been most of the way there: KOReader, a third-party reading application for the Kobo, has an embedded terminal emulator that hands root access to the device to you, no questions asked. You just drop whatever command-line binaries you want in <code>/mnt/onboard/.adds/koreader/plugins/terminal.koplugin/</code>, and as long as they're compiled for Linux <code>armv7l</code> they're good to go. For a while, the terminal emulator had problems with <code>ncurses</code>, so you couldn't use any TUI programs and had to stick exclusively to the command line with its one-off commands... but somewhere along the way that got fixed, so now you can use your fancy Gemini browsers and the built-in <code>vi</code> and anything else that requires an actual text-based interface.</p>
<p>The only problem with this setup is that the Kobo Libra H2O doesn't support USB OTG out-of-the-box. That means, even if you have a special adapter, you can't use an external keyboard. You're stuck with the virtual keyboard on-screen, which is okay for small operations but <em>highly</em> uncomfortable for long typing sessions like writing, which is mainly what I'd use the extra functionality for. It's also a pain in the ass to use the virtual keyboard to type any special characters like the pipe symbol or an exclamation mark.</p>
<p>Well, apparently almost a year ago <a href="https://web.archive.org/web/20230120183715/https://github.com/koreader/koreader/releases/tag/v2022.11">KOReader added external keyboard support for Kobo devices</a>. You need a powered USB OTG adapter as the Kobo won't supply enough power to recognize that there's a device connected, but once you have the keyboard and the power source (I use one of those cheap portable battery packs, because if I have to be tethered to an outlet, I'd rather just use an actual computer) connected, KOReader recognizes that there's a keyboard plugged in and enables keyboard shortcuts in the interface and keyboard input for the text editor and terminal.</p>
<p>...Except that the shift button doesn't work properly.</p>
<p>On a standard US QWERTY keyboard, pressing Shift and one of the number keys on top makes a special character. Shift and 1, for example, make an exclamation mark. Shift and 2 make an <code>@</code> symbol. Shift and 3 make a hash. Shift and 4 make a dollar sign. Et cetera. However, the Kobo doesn't seem to recognize when the Shift key is being held down for any key <em>other than the twenty-six alphabetic keys.</em> I can TYPE IN ALL CAPS WITH THE SHIFT BUTTON HELD DOWN, but I can't make any underscores or question marks or double quotation marks. "Who cares?" you might ask, in which case I would respond, "Well, when writing, the characters often speak, and they accentuate their sentences! Which creates a problem: if I have to constantly capitulate to the keyboard on the screen to make special characters, then I will always be losing my rhythm (and possibly my train of thought as well)."</p>
<p>How keyboards work in Linux is pretty complicated, but the gist is this: when you press a key on your keyboard, it doesn't send that key specifically; it sends a "keycode" to the kernel, which decides what key that corresponds to. So when I press the A key on my laptop keyboard, it doesn't send an A, it sends a code which can be seen with <code>sudo evtest</code>:</p>
<p><code>Event: time 1693317010.094300, type 1 (EV_KEY), code 30 (KEY_A), value 1</code></p>
<p>As evidenced by the log, the A key corresponds with code 30. Which matches <a href="https://archive.ph/https://raw.githubusercontent.com/koreader/koreader/master/plugins/externalkeyboard.koplugin/event_map_keyboard.lua">the keycode map KOReader uses to interpret keyboard events on Kobo devices</a>.</p>
<p>So I thought that maybe the Shift key wasn't being captured properly on the Kobo, which was causing Shift and 1 to output 1 instead of an exclamation mark. So I ran <code>evtest --grab /dev/input/event4</code> on the Kobo:</p>
<pre>
Event: time 1693317622.024915, type 4 (Misc), code 4 (ScanCode), value 70004
Event: time 1693317554.992894, type 4 (Misc), code 4 (ScanCode), value 700e1
Event: time 1693317640.632890, type 4 (Misc), code 4 (ScanCode), value 700e1
Event: time 1693317640.744919, type 4 (Misc), code 4 (ScanCode), value 7001e
</pre>
<p>For whatever reason, the Kobo's kernel reports the key presses not as type 1 but as type 4, all with the same codes. The value is what's important here. According to the values, <a href="https://web.archive.org/web/20230829140343/https://deskthority.net/viewtopic.php?t=24076">the first key press is our example, the A key</a>. The second one is the Shift key all by itself. The third and fourth ones are when I attempted to make that exclamation mark by pressing Shift and 1 together. As you can see, the exclamation mark isn't its own key put together by the keyboard's firmware or whatever; it's something else in the system that sees the Shift and 1 being pressed at the same time and chooses to interpret that as an exclamation mark. And that "something else" on the Kobo only likes letters.</p>
<p>But we <em>know</em> that the Kobo can handle special characters. KOReader has to <em>somehow</em> map the hardware "previous page" and "next page" buttons to, well, turning the pages of the book back or forwards.</p>
<p>It turns out that our salvation lies in that keycode map in KOReader. If you <a href="https://archive.md/https://raw.githubusercontent.com/koreader/koreader/master/plugins/externalkeyboard.koplugin/event_map_keyboard.lua">take another look at it</a>, you can see that not all the keys match up to an ASCII equivalent. For example, Page Up, or whatever key sends keycode 104, gets mapped to "LPgBack". Which matches our standard laptop keyboard again:</p>
<p><code>Event: time 1693318576.571605, type 1 (EV_KEY), code 104 (KEY_PAGEUP), value 0</code></p>
<p><strong>Theoretically we should be able to take an arbitrary key on the keyboard, capture its keycode, and then put it into this map to make it output whatever character we want.</strong></p>
<p>So let's add the bracket keys, which got omitted for some reason:</p>
<p><code>[26] = "[", [27] = "]",</code></p>
<p>And then let's change all the F1 through F12 buttons to be the special characters locked behind the number keys, as well as the question mark and double quotations:</p>
<pre>
[59] = "!",
[60] = "@",
[61] = "#",
[62] = "$",
[63] = "%",
[64] = "^",
[65] = "&amp;",
[66] = "*",
[67] = "(",
[68] = ")",
[87] = "?",
[88] = '"',
</pre>
<p>And just for my cheapo wireless keyboard I got off eBay, let's make the shoulder L and R buttons be the same as the left and right arrow keys:</p>
<p><code>[272] = "Left", [273] = "Right",</code></p>
<p>Save the map and restart KOReader, and the keys should now be working properly as mapped. Still no proper Shift, though...</p>
</div>
<hr>
<div class="box">
<p align=right>CC BY-NC-SA 4.0 &copy; Vane Vander</p>
</div>
</article>
<script data-goatcounter="https://stats.letsdecentralize.org/count"
async src="//stats.letsdecentralize.org/count.js"></script>
<noscript>
<img src="https://stats.letsdecentralize.org/count?p=/blog/2023/september/koreader.html">
</noscript>
</body>
</html>

View File

@ -19,6 +19,7 @@
<div class="box">
<h2>2023</h2>
<ul>
<li>September 1 - <a href="./2023/september/koreader.html">Workaround for external keyboards to make special characters in KOReader</a></li>
<li>August 10 - <a href="./2023/august/interview.html">Every damn day I get emails</a></li>
<li>July 1 - <a href="./2023/july/FULL_TOR.html">It's never been a better time to dive into Tor</a></li>
<li>June 1 - <a href="./2023/june/torward.html">Look Torward, Young Vane</a></li>

View File

@ -11,7 +11,7 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
as of 2023-04-13:
as of 2023-08-30:
I have full administrative control of the following domains and their subdomains:
- - mayvaneday.art
@ -23,7 +23,7 @@ I have full administrative control of the following domains and their subdomains
The following Tor hidden services are mine, and I have sole access to the private keys:
- - meynethaffeecapsvfphrcnfrx44w2nskgls2juwitibvqctk2plvhqd.onion (MayVaneDay)
- - xanthexikes7btjqlkakrxjf546rze2n4ftnqzth6qk52jdgrf6jwpqd.onion (Let's Decentralize)
- - hikariu7kodaqrmvu3c3y422r6jc7gqtpvvbry6u7ajvranukx6gszqd.onion (Let's Decentralize)
- - blapi36sowfyuwzp4ag24xb3d4zdrzgtafez3g3lkp2rj4ho7lxhceid.onion (Dead End Shrine Online)
The following I2P "eepsites" are mine, and I have sole access to the private keys:
@ -37,11 +37,18 @@ The following Freenet sites are mine, and I have sole access to the private keys
- - USK@NXLolHtxd-LrJ2JvE6qulMUL2g5QNaIV8yXhKO9UonY,hLlv0NAH-aJJIQv3duulegWKR3yNbvIrfinvva1R1T8,AQACAAE/letsdecentralize/-1/ (Let's Decentralize)
- - USK@3igGCjaVr8BNYRhuRka8BA50089XeH-uOq1~m8FZ5KQ,pzggo6unfI9aZTSYJvimOyFFuQAQwrPYxpnbHN8k~L4,AQACAAE/deadendshrine/-1/ (Dead End Shrine Online)
FOR LEGAL INQUIRIES, EMAIL:
To contact me, email any of the following:
vanevander AT mayvaneday DOT org
FOR BUSINESS INQUIRIES, EMAIL:
lethe AT deadendshrine DOT online
DO NOT CONTACT ME OTHERWISE FOR ANY OTHER REASON
lethe AT beltane DOT email
vane AT beltane DOT email
Do NOT email me if I've previously said "don't contact me ever again". I shouldn't
have to say this since it seems blatantly obvious, but apparently men are still
illiterate in Current Year. (And no, it's not sexist to observe that on both occasions
the offenders were male.)
To all the women who've ever mailed me to say that my posts helped them make themselves
even just a little bit more free, or the anons who've mailed to say my poetry inspires
them, a sincere thank you is in order. Your kind words give me the strength to go on.
If you're browsing this site though a Git repository,
the GPG fingerprint used for signing SHOULD be:
@ -49,17 +56,18 @@ the GPG fingerprint used for signing SHOULD be:
which SHOULD match lethe AT deadendshrine DOT online and "/lethe.gpg" in this repo.
CURRENT OFFICIAL GIT REPO MIRRORS:
https://codeberg.org/lethe/mayvaneday (currently private due to stalking)
https://git.letsdecentralize.org/lethe/mayvaneday
https://codeberg.org/lethe/mayvaneday
https://notabug.org/lethe/mayvaneday
https://gitlab.lain.la/lethe/mayvaneday
https://git.disroot.org/lethe/mayvaneday
http://kgtz2pmmov5jfvn3z4mqryffjnnw6krzrgxxoyaqhqckjrr4pckyhsqd.onion/lethe/mayvaneday (mirror of above)
http://gg6zxtreajiijztyy5g6bt5o6l3qu32nrg7eulyemlhxwwl6enk6ghad.onion/lethe/mayvaneday
http://snw2i6zk7htxx7dtejpc7mq7omk7zxkpoczi3k6af3rmpmuxfvig2rid.onion/lethe/mayvaneday
http://it7otdanqu7ktntxzm427cba6i53w6wlanlh23v5i3siqmos47pzhvyd.onion/cetra/mayvaneday
http://yylovpz7taca7jfrub3wltxabzzjp34fngj5lpwl6eo47ekt5cxs6mid.onion/cetra/mayvaneday
http://pmo2bva2xhlxydq7zfswb6v4x4e32p3mj446tblj3hfi2rygh3lraqyd.onion/lethe/mayvaneday
http://[300:ad1e:2e16:553f::132]/lethe/mayvaneday
https://gitea.phreedom.club/lethe/mayvaneday (mirror of above)
https://gitea.phreedom.club/lethe/mayvaneday
Finally, my GPG public key is:
@ -95,14 +103,15 @@ Ipzl6ecL3upkGrfo0MVNDVcpFiq1t7kh81pi
- -----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP SIGNATURE-----
iQEzBAEBCgAdFiEEq2j4OrvQF4SeDEtjVj/VgT2D7rUFAmQ4mvMACgkQVj/VgT2D
7rVcMAf8DbPyRPjXdaZjTjNPA5WKQK8I8g7/v6RLYiTCg2MEibaZHmwd6Gq6GL4o
jYogHLByc7dVflFqHzq7dKm7kDIdWlYG5zaRZwtDv7rpz/yofJzrIAy7Ri14fXTL
9Tz8L0A8QV/m26E17TdWJvkLUAI9eCBYbnN27KzhOSUEFDcCYJbx3K4kSNr6Pnbw
dUlA329ou/9N0kGRVZV2vZ/rpDfl9XoTMPWWYy6eVEf4afilMsDTWJd0RLRbw4Hj
qVpdffEIQOBE+j0t+jJxXPxoX9lS3JMhiGc4R9d67upVpjIMECedSUXCA3EBbX7B
18Hu7a7jbAxNU1Vidk2mE1XEL5A5Sg==
=J2ha
iQFOBAEBCgA4FiEEq2j4OrvQF4SeDEtjVj/VgT2D7rUFAmTvas0aHHZhbmV2YW5k
ZXJAbWF5dmFuZWRheS5hcnQACgkQVj/VgT2D7rVBkAf/TA0sp8NydTUT2Fi6WsAk
7XA7E/uMw5VNIoidQOJQ7puxjMBOjtfZwoBRYW5/shZ6Ijw24CdVovuD5HOoB51g
6IrrnWjaHJPq5YQt0vjacXxSQKxULNwWHd5VIGwZOEMTkooPO6cSbpe5M2cXsBMu
xLWp5eUfks1LVrAsxvrGFzwAB6Ih6bRRS09y5V7YcAQw83hAKYaNRKPpP0GvVJfK
Jjbq2prcvc6Iu/I4RA0H8NJiZtPsCMv5BrxG3EHJOK94STajzR85sXtMSXLJZfBt
PBCfaHCSWF8/9VcvtF0vv55DBHeyvTpO9ChgaQzzwIf1Ks9V9u37Mm2saFjTfa2w
ZA==
=mjpm
-----END PGP SIGNATURE-----
</pre>
</body>

BIN
img/urbit2/astrolabe.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
img/urbit2/bill.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
img/urbit2/emoji.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
img/urbit2/group.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
img/urbit2/lag.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
img/urbit2/meme.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
img/urbit2/quote.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
img/urbit2/s3.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -50,6 +50,7 @@
<div class="box">
<h3>Announcement Box</h3>
<ul>
<li>2023-08-30: So Vultr decided to destroy my server without warning. Most services I was able to pull back online on a different VPS provider without too much hassle, but I did unfortunately lose a few private keys to hidden services due to a corrupted backup. Thanks, Vultr, you pieces of shit! Maybe <em>email me next time</em> you want to open support tickets about "muh high CPU usage". Some of us like to compile programs from source... Anyways, <a href="http://hikariu7kodaqrmvu3c3y422r6jc7gqtpvvbry6u7ajvranukx6gszqd.onion">Let's Decentralize has a different onion link now</a>. Links across all three sites should be updated within the next day.</li>
<li>2023-07-10: <a href="http://libreddit.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion/r/KiDIcaruS/comments/14h4jvt/i_strongly_advise_you_do_not_initiate_trouble/">[me_irl]</a> (Moving into a new place. Expect downtime. Will update soon.)</li>
<li>2023-04-25: I've been employed for about a month. Gotten perfect scores on all my performance reviews so far. Life is okay for now.</li>
<li>2023-04-13: Codeberg mirror is down until Forgejo implements user blocking.</li>

View File

@ -51,5 +51,8 @@ Disallow: /
User-agent: SpiderLing
Disallow: /
User-agent: GPTBot
Disallow: /
User-agent: *
Disallow: /